home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / terms / kermit / b / ckvtio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-09  |  78.8 KB  |  2,675 lines

  1. #ifndef VMS
  2. # error -- CKVTIO.C is used only on the VMS(tm) or OpenVMS(tm) Operating System
  3. #endif /* VMS */
  4.  
  5. #ifdef __ALPHA
  6. # define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) AXP(tm)";
  7. #else
  8. # ifdef VAX
  9. #  module ckvtio "2.0-056"
  10. #  define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) VAX(tm)";
  11. # else
  12. #  ifdef __GNUC__
  13. #   define CKVTIO_OS_ARCH_STRING " OpenVMS(tm) VAX(tm) (GCC)";
  14. #  else
  15. #   error -- CKVTIO.C unknown architecture, neither VAX(tm) nor AXP(tm)
  16. #  endif /* __GNUC__ */
  17. # endif /* VAX */
  18. #endif /* __ALPHA */
  19. /*
  20.   Module version number and date.
  21.   Also update the module number above accordingly.
  22. */
  23. char *ckxv = "Communications I/O 2.0(056), 8 Aug 93";
  24. /*
  25.   This is the default architecture and operating system herald string.
  26.   It is redetermined dynamically in sysinit() below.  
  27. */
  28. char *ckxsys = CKVTIO_OS_ARCH_STRING;
  29.  
  30. /*  C K V T I O  --  Terminal and Interrupt Functions for VAX/VMS  */
  31.  
  32. /* C-Kermit interrupt, terminal control & i/o functions for VMS systems */
  33.  
  34. /*
  35.   Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  36.   Columbia University Academic Information Systems, New York City.
  37.  
  38.   Copyright (C) 1985, 1993, Trustees of Columbia University in the City of New
  39.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  40.   sold for profit as a software product itself, nor may it be included in or
  41.   distributed with commercial products or otherwise distributed by commercial
  42.   concerns to their clients or customers without written permission of the
  43.   Office of Kermit Development and Distribution, Columbia University.  This
  44.   copyright notice must not be removed, altered, or obscured.
  45. */
  46.  
  47. /* Edit History
  48.  *
  49.  * Originally adapted to VMS by:
  50.  * Stew Rubenstein, Harvard University Chemical Labs, 1985.
  51.  *
  52.  * Cast of characters:
  53.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  54.  * wb  William Bader  Lehigh University
  55.  * mab Mark Buda      DEC
  56.  * fdc Frank da Cruz  Columbia U
  57.  * HG  Hunter Goatley Western KY U
  58.  * jh  James Harvey   Indiana / Purdue U
  59.  * tmk Terry Kennedy  St Peters College
  60.  * MM  Martin Minow   DEC
  61.  * DS  Dan Schullman  DEC
  62.  * LT  Lee Tibbert    DEC
  63.  * js  James Sturdevant
  64.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  65.  * 006  8-May-85 MM   Got rid of "typeahead buffer" code as it didn't
  66.  *              solve the problem of data overruns at 4800 Baud.
  67.  *              Added vms "read a char" routine that checks for
  68.  *              CTRL/C, CTRL/Z, etc.
  69.  * 007 16-May-85 fdc  Changed calling convention of ttopen(), make it
  70.  *                    set value of its argument "lcl", to tell whether
  71.  *                    C-Kermit is in local or remote mode.
  72.  * 008 11 Jun 85 MM   Fix definition of CTTNAM
  73.  * 009 18 Jun 85 fdc  Move def of CTTNAM to ckcdeb.h so it can be shared.
  74.  * 010 25 Jun 85 MM   Added sysinit() to open console.
  75.  * 011  5 Jul 85 DS   Treat hangup of closed line as success.
  76.  * 012 11 Jul 85 fdc  Add gtimer(), rtimer() for timing statistics.
  77.  * 013 14 Sep 87 fdc  Add parity strip to ttinl(), add syscleanup().
  78.  * 014 14 Feb 89 mab  Make break REALLY work.  Add IOSB's to all QIO's.
  79.  * 015 26 Feb 89 mab  Add dcl exit handler and minor cleanup
  80.  * 016 23-Mar-89 mab  Add IO$M_BREAKTHRU to IO$_WRITEVBLK.
  81.  *              Add zchkspd() function to check for valid speed.
  82.  * 017 04-Apr-89 mab  Fix some minor bugs to local/remote code
  83.  * 018 23-Apr-89 mab  Add some of Valerie Mates' parity changes.
  84.  * 019 25-Apr-89 mab  Change baud to 110 for V4.x break routine as
  85.  *               50 baud is not supported on most Muxes by VMS.
  86.  * 020 13-Jun-89 mab  Fix on exquota problem on qiow(readvblk)
  87.  * 021 08-Jul-89 mab  Add ^C/^Y abort server mode code.
  88.  * 022 11-May-90 mab  Add V5A code 
  89.  * 023 20-Jul-90 wb   Add support for old VAX C and VMS versions
  90.  * 024 22-Sep-90 wb   Fixes to cps/bps confusion
  91.  * 025 26-Sep-90 tmk  Fix the ztime() function
  92.  * 026 29-Sep-90 tmk  Edit 024 cause a server command to give some blither-
  93.  *              ings about unsupported line speeds.  Added a simple hack
  94.  *              to exit quietly if the passed speed is 0.  Adventurous
  95.  *              maintainers may want to look in ttpkt(), where ttsspd()
  96.  *              is being called with a value of -1/10.
  97.  * 027 11-Oct-90 fdc  Made ttol return number of chars successfully written.
  98.  *                    Made ztime() use ctime() in all cases.
  99.  *                    Another fix (from tmk) for bps/cps confusion.
  100.  *                    Wrapped source lines longer than 80 characters.
  101.  * 028 18-Oct-90 fdc  Added comments to concb() and vms_getchar() to show
  102.  *                    how to make Ctrl-C trap work.  Didn't actually do it,
  103.  *                    though, because Ctrl-Y apparently still can't be caught.
  104.  *                    Also, more minor reformatting.  Adjust time() declare.
  105.  *                    Added support for automatic parity sense in ttinl(),
  106.  *                    within #ifdef PARSENSE conditionals.  Built with PARSENSE
  107.  *                    defined, works ok.
  108.  * 029  5-Apr-91 fdc  Extensive reworking of many routines to allow for
  109.  *              network connections, addition of TGV MultiNet support.
  110.  * 030 31-Aug-91 tmk  Fix problem with INPUT statements not timing out due to
  111.  *              extraneous rtimer() inside gtimer().
  112.  * 032  6-Nov-91 fdc  Correct parity problem.
  113.  * 032  6-Nov-91 fdc  Cosmetic cleanup in sysinit().
  114.  * 033 14-Jan-91 fdc  Fix to get_qio_maxbuf_size to prevent crashes:
  115.  *                    remove "&" from "!test_qio(ttychn,max,&tmpbuf)",
  116.  *                    from John Schultz at 3M.
  117.  * 034  8-Feb-92 fdc  Don't change EIGHTBIT setting in ttvt, concb, or conbin.
  118.  *                    Set EIGHTBIT in ttpkt only if parity is not NONE.  From
  119.  *                    Alan Robiette, Oxford U, UK.
  120.  * 035 10-Jun-92 fdc  Added code from Ray Hunter of The Wollongong Group to
  121.  *                    support both WIN/TCP and TGV Multinet.  Network section
  122.  *                    of contti() redone to eliminate polling loop.  It's
  123.  *                    infinitely faster.
  124.  * 036 11-Jun-92 tmk  Fixed up edit 034 so 8-bit characters could be passed
  125.  *                    in connect mode.
  126.  * 037 19-Jun-92 fdc  Totally rewrote all the serial input and mode-setting 
  127.  *                    routines in this module to use nonblocking, fully
  128.  *                    buffered input and to share a common buffer.  All
  129.  *                    serial-line input is localized to a single routine,
  130.  *                    txbufr(), which, in turn is known only to ttinc().  The
  131.  *                    other input routines, ttxin() and ttinl(), simply call
  132.  *                    ttinc().  ttchk() and ttflui() are totally cognizant of
  133.  *                    the buffer.  ttinl() now recognizes packets with
  134.  *                    printable start characters and/or lacking terminators,
  135.  *                    so VMS C-Kermit can now engage in "Doomsday Kermit"
  136.  *                    protocol.  ttvt() and ttpkt() were merged into a single
  137.  *                    new (static) routine, ttbin(), which no longer puts the
  138.  *                    device into PASALL mode (which defeats flow control).
  139.  *                    Added ttsndlb() to send a Long BREAK.  Much fine-tuning,
  140.  *                    testing, and filling-in remains to be done, including
  141.  *                    (a) make ttopen() and ttclos() aware of LAT devices; (b)
  142.  *                    check remaining BYTLM quota before issuing a read, (c)
  143.  *                    integrate network and serial buffers, and much more.
  144.  *                    Anyway, this code seems to run faster than ever before,
  145.  *                    and for the first time I can actually use sliding
  146.  *                    windows AND long packets on my 8-year old MicroVAX-II.
  147.  * 038 28-Jun-92 tmk  Additional work on edit 37, general cleanup of old defs.
  148.  * 039  1-Jul-92 wb   Changes for VMS 4.4.
  149.  * 040  4-Jul-92 tmk  Add modem signal support (ttgmdm routine).
  150.  * 041  4-Jul-92 tmk  Add tgetent(), worker routine for el-cheapo curses.
  151.  * 042  4-Jul-92 jh   Enable typeahead in ttbin().
  152.  * 043 21-Aug-92 fdc  Make default flow control be KEEP instead of Xon/Xoff.
  153.  * 044  6-Sep-92 fdc  Put default flow back to Xon/Xoff, but allow KEEP to be
  154.  *                    used to restore device's original flow-control setting.
  155.  * 045 23-Sep-92 fdc  Add sleep(1) to tthang().  Seems to fix HANGUP command.
  156.  *                    Suggested by Lee Tibbert.  Change ttbin() to use global
  157.  *                    flow variable rather than its flow parameter for setting
  158.  *                    flow control, to ensure the desired type of flow control
  159.  *                    is used during DIAL operations.
  160.  * 046 26-Sep-92 fdc  Change sleep(1) in tthang() to sleep(3).  Annoying but
  161.  *                    necessary.  IO$M_HANGUP takes about 3 seconds, but the
  162.  *                    sys$qiow() function returns immediately instead of
  163.  *                    waiting for the action to complete.
  164.  * 047 08-Oct-92 HG   Add call to sys$alloc in ttopen() to prevent user with
  165.  *              SHARE from getting port in use.  Some add'l cleanup.
  166.  * 048 12-Oct-92 LT   Minor changes to support DEC TCP/IP (nee UCX).
  167.  * 049 25-Oct-92 fdc  Adapt cancio() to DEC TCP/IP.
  168.  *                    Remove superfluous ttflui() call from ttpkt().
  169.  *                    Add code from Lee Tibbert to sysinit() to figure out OS
  170.  *                    and architecture name at runtime.
  171.  * 050 18-Nov-92 fdc  Read from comm device in 1024-byte chunks, rather than
  172.  *                    trusting the qio_maxbuf_size.  This should reduce BYTLM
  173.  *                    quota-exceeded errors.  Suggested by tmk as a temporary
  174.  *                    workaround.
  175.  * 051 10-May-93 fdc  Add support for SET TRANSFER CANCELLATION.
  176.  * 052 16-May-93 fdc  Change VMSTCPIP to TCPIPLIB to agree with new CKCNET.H.
  177.  * 053 16-May-93 fdc  ANSIfication for GNU CC, from James Sturdevant.
  178.  * 054 08-Jun-83 fdc  Add TT$M_LOCALECHO and TT$M_ESCAPE to the terminal modes
  179.  *                    we handle, to prevent "getty babble" with modems, VAX
  180.  *                    PSI, etc.
  181.  * 055 16-Jun-93 fdc  Edit 054 only affected ttbin().  This edit does the same
  182.  *                    for conbin() and concb().  Fixes double echoing in
  183.  *                    command mode when coming in via VAX PSI.
  184.  * 056  8-Aug-93 fdc  Add types to all function declarations.
  185.  */
  186.  
  187. /*
  188.  Variables available to outside world:
  189.  
  190.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  191.    dfloc  -- 0 if dftty is console(remote), 1 if external line(local).
  192.    dfprty -- Default parity
  193.    dfflow -- Default flow control
  194.    ckxech -- Flag for who echoes console typein:
  195.      1 - The program (system echo is turned off)
  196.      0 - The system (or front end, or terminal).
  197.    functions that want to do their own echoing should check this flag
  198.    before doing so.
  199.  
  200.    backgrd
  201.      Flag indicating program not executing interactively.
  202.      Used to ignore INT and QUIT signals, suppress messages, etc.
  203.    vms_status
  204.      Status returned by most recent VMS system service,
  205.      can be used for error reporting.
  206.  
  207.  Functions for assigned communication line (either external or console tty):
  208.  
  209.    ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
  210.    ttclos()                -- Close & reset the tty, releasing any access lock.
  211.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  212.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  213.                 or in DIALING or CONNECTED modem control state.
  214.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  215.    ttinc(timo)             -- Timed read character from tty.
  216.    ttchk()                 -- See how many characters in tty input buffer.
  217.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  218.    ttol(string,length)     -- Write a string to the tty.
  219.    ttoc(c)                 -- Write a character to the tty.
  220.    ttflui()                -- Flush tty input buffer.
  221.    tt_cancel()           -- Cancel any asynch I/O to tty
  222. */
  223.  
  224. /*
  225. Functions for console terminal:
  226.    congm()   -- Get console terminal modes.
  227.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  228.    conbin(esc) -- Put the console in binary (raw) mode.
  229.    conres()  -- Restore the console to mode obtained by congm().
  230.    conoc(c)  -- Unbuffered output, one character to console.
  231.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  232.    conola(s) -- Unbuffered output, array of lines to the console, CRLFs added.
  233.    conxo(n,s) -- Unbuffered output, n characters to the console.
  234.    conchk()  -- Check if characters available at console (bsd 4.2).
  235.         Check if escape char (^\) typed at console (System III/V).
  236.    coninc(timo)  -- Timed get a character from the console.
  237.    conint()  -- Enable terminal interrupts on the console if not background.
  238.    connoi()  -- Disable terminal interrupts on the console if not background.
  239.    contti()  -- Get a character from either console or tty, whichever is first.
  240.  
  241. Time functions
  242.  
  243.    msleep(m) -- Millisecond sleep
  244.    ztime(&s) -- Return pointer to date/time string
  245.    rtimer()  -- Reset elapsed time counter
  246.    gtimer()  -- Get elapsed time
  247. */
  248.  
  249. /* Includes */
  250. #include "ckcdeb.h"            /* Formats for debug() */
  251. #include "ckcasc.h"
  252. #include "ckcker.h"
  253.  
  254. #include "ckvvms.h"
  255.  
  256. #include <stdio.h>            /* Unix Standard i/o */
  257. #include <signal.h>            /* Interrupts */
  258. #include <setjmp.h>            /* Longjumps */
  259. #include <iodef.h>
  260. #include <ttdef.h>
  261. #include <tt2def.h>
  262. #include <ssdef.h>
  263. #include <descrip.h>
  264. #include <dvidef.h>
  265. #include <dcdef.h>
  266. #include <devdef.h>
  267. #include <time.h>
  268. #include <syidef.h>
  269.  
  270. /* lt 1992-10-08 Begin
  271.  */
  272. #ifndef __ALPHA
  273. # ifndef __GNUC__
  274. #  define void int
  275. # endif /* __GNUC__ */
  276. #endif /* __ALPHA */
  277. /* lt 1992-10-08 End
  278.  */
  279.  
  280. #if defined(VMS_V40) || defined(VMS_V42) || defined(VMS_V44) /* No starlet */
  281. #define IO$_TTY_PORT 41
  282. #else
  283. #include <starlet.h>
  284. #endif /* (Old VMS) */
  285.  
  286. /* Macros */
  287.  
  288. #define xx_inc(timo) (--ttxbn>=0?ttxbuf[ttxbp++]:txbufr(timo))
  289.  
  290. /* Declarations */
  291.  
  292. #ifndef __ALPHA
  293. #ifndef MULTINET
  294.     time_t time();
  295. #endif
  296. #endif
  297.     char *ctime();            /* Convert to asctime() string */
  298.  
  299.     void dcl_exit_h();            /* Exit handler */
  300.     unsigned long int vms_assign_channel();
  301.     VOID tt_cancel();
  302.  
  303. /* dftty is the device name of the default device for file transfer */
  304. /* dfloc is 1 if dftty is the user's console terminal, 0 if an external line */
  305.  
  306.     char *dftty = CTTNAM;
  307.     int dfloc = 0;            /* Default location is local */
  308.     int dfprty = 0;            /* Parity (0 = none) */
  309.     int ttprty = 0;            /* Parity in use */
  310.     int ttpflg = 0;            /* Parity not sensed yet. */
  311.     int backgrd = 0;            /* Running in "background" (no tty) */
  312.     static int ttpmsk = 0377;
  313.     int ttmdm = 0;                      /* Modem in use. */
  314.     int dfflow = FLO_XONX;        /* Default flow control is Xon/Xoff */
  315.     int batch = 0;            /* Assume interactive */
  316.     int ttcarr = CAR_AUT;        /* Carrier Handling Mode */
  317.     int tvtflg = 0;            /* Flag that ttvt has been called */
  318.     long ttspeed = -1;            /* For saving speed */
  319.     int ttflow = -9;            /* For saving flow */
  320.  
  321. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  322.  
  323. unsigned int vms_status;        /* Used for system service return status */
  324.  
  325. /* Structures used within this module */
  326.  
  327. #ifndef TT$C_BAUD_38400
  328. #define TT$C_BAUD_38400    0x11
  329. #endif /* TT$C_BAUD_38400 */
  330.  
  331. static struct {
  332.     unsigned char dec;
  333.     unsigned short int line;
  334.     } ttspeeds[] = {
  335.     {TT$C_BAUD_50,       5},
  336.     {TT$C_BAUD_75,       7},
  337.     {TT$C_BAUD_110,     11},
  338.     {TT$C_BAUD_134,     13},
  339.         {TT$C_BAUD_150,     15},
  340.     {TT$C_BAUD_300,     30},
  341.     {TT$C_BAUD_600,     60},
  342.     {TT$C_BAUD_1200,   120},
  343.     {TT$C_BAUD_1800,   180},
  344.     {TT$C_BAUD_2000,   200},
  345.     {TT$C_BAUD_2400,   240},
  346.     {TT$C_BAUD_3600,   360},
  347.     {TT$C_BAUD_4800,   480},
  348.     {TT$C_BAUD_7200,   720},
  349.     {TT$C_BAUD_9600,   960},
  350.     {TT$C_BAUD_19200, 1920},
  351.     {TT$C_BAUD_38400, 3840},
  352.     {0,                   0} };
  353.  
  354. /* Declarations of variables global within this module */
  355.  
  356. static long tcount = 0;            /* For timing statistics */
  357.  
  358. static char brkarray[] = {        /* For simulating BREAK */
  359.  
  360.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
  361.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
  362.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
  363.  '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
  364. };
  365.  
  366. int ttyfd = -1;                /* TTY file descriptor */
  367.  
  368. static int conif = 0,            /* Console interrupts on/off flag */
  369.     conclass = 0,            /* Console device type */
  370.     cgmf = 0,                /* Flag that console modes saved */
  371.     xlocal = 0,                         /* Flag for tty local or remote */
  372.     ttychn = 0,                /* TTY i/o channe; */
  373.     conchn = 0,                /* Console i/o channel */
  374.     con_queued = 0,            /* console i/o queued in contti() */
  375.     tt_queued = 0,            /* tty i/o queued in contti() */
  376.     conch,                /* console input character buffer  */
  377.     curcarr = 0,            /* Carrier mode: require/ignore */
  378.     ttch;                /* tty input character buffer */
  379. static unsigned char escchr;        /* Escape or attn character */
  380. static char ttnmsv[80];              /* copy of open path for tthang */
  381. static char lclnam[80];            /* Local device name */
  382.  
  383. static char tt_fulldevnam[65];
  384. static struct dsc$descriptor_s tt_fulldevnam_d;    /* Descriptor for line name */
  385.  
  386. static long int qio_maxbuf_size;    /* Maximum size of QIO to succeed */
  387. static unsigned long dclexh_status;    /* Exit status for DCL exit handler */
  388. static struct iosb_struct coniosb, ttiosb, wrk_iosb;
  389. static struct tt_mode
  390.     ttold, ttraw, tttvt,        /* for communication line */
  391.     ccold, ccraw, cccbrk,        /* and for console */
  392.     cctmp;
  393.  
  394. /* Network support */
  395.  
  396. #include "ckcnet.h"            /* Network type symbols */
  397. extern int ttnet;            /* Network type */
  398. static int network = 0;            /* 1 if network connection */
  399. extern int xfrcan, xfrchr, xfrnum;    /* Transfer cancellation */
  400.  
  401. /* Needed for parity fixes in edit 036 */
  402. extern int parity;            /* current parity setting */
  403.  
  404. /*
  405.   New buffered input scheme.
  406. */
  407. #define TTXBUF
  408.  
  409. #ifdef TTXBUF
  410. #define TTXBUFL RBSIZ            /* Internal buffer size */
  411.  
  412. CHAR     ttxbuf[TTXBUFL+1];        /* The buffer */
  413. int     ttxbp = 0, ttxbn = 0;        /* Buffer pointer and count */
  414.  
  415. /*
  416.   T X B U F R
  417.  
  418.   Read bytes from communication device into internal buffer ttxbuf[].
  419.   To be called only when input buffer is empty, i.e. when ttxbn == 0.
  420.  
  421.   Other comm-device reading routines, like ttinc, ttinl, ttxin, should check
  422.   the internal buffer first, and call this routine for a refill if necessary.
  423.  
  424.   When data is read successfully, the first character is returned and
  425.   the global buffer count, ttxbn, is set to the number of characters remaining
  426.   in ttxbuf after it, and the global buffer offset, ttxbp, is set to 1.
  427.  
  428.   When data is not read successfully, -1 is returned indicating a timeout,
  429.   or -2 indicating disconnection.
  430. */
  431. int
  432. txbufr(timo) int timo; {        /* TT Buffer Read */
  433.     int count;
  434.     int func;                /* Read function code */
  435.     int mask;                /* Event mask */
  436.     int vms_status;            /* Read QIO return code */
  437.     static int trmmsk[2] = {0,0};    /* Terminal read break mask */
  438.     static int trmlong[8] = {0,0,0,0,0,0,0,0}; /* Break on nothing */
  439.  
  440.     debug(F101,"txbufr entry, ttxbn","",ttxbn);
  441.     if (ttxbn > 0) {            /* Should not be called */
  442.     debug(F101,"txbufr called with ttxbn","",ttxbn); /* if ttxbn > 0! */
  443.     ttxbn--;
  444.     return(ttxbuf[ttxbp++] & 0xff);
  445.     }
  446.     ttxbp = ttxbn = 0;            /* Reset buffer pointer and count */
  447.     ttxbuf[0] = NUL;
  448.  
  449.     if (timo < 0)            /* Be safe */
  450.       timo = 0;
  451.     debug(F101,"txbufr timo","",timo);
  452.  
  453.     func = IO$_READVBLK | IO$M_NOFILTR;    /* Read virtual block, no filtering */
  454.     trmmsk[0] = sizeof(trmlong);    /* No terminators */
  455.     trmmsk[1] = (int)&trmlong;        /* Keep all characters */
  456.  
  457. /*
  458.   We try to scoop up as many as we can in a nonblocking read (timed, but with
  459.   timeout value of 0).  This is supposed to return immediately with up to
  460.   "count" characters placed in our buffer.
  461. */
  462.     count = TTXBUFL;            /* Maximum characters to read */
  463.  
  464. #ifdef COMMENT
  465. /*
  466.   This causes problems because we are not adjusting according to the CURRENT
  467.   BYTLM quota, but rather to the one that was obtained when Kermit started.
  468.   Since the quota is dynamic, it might have been reduced since then.
  469. */
  470.     if (count > qio_maxbuf_size)
  471.     count = qio_maxbuf_size;
  472. #else
  473. /*
  474.   So for now we use 1024, which tends to be smaller than the value obtained
  475.   above.  Later, this should be changed to find out the remaining BYTLM quota
  476.   and use that instead.  This size can be overridden at compile time by
  477.   defining the symbol...
  478. */
  479. #ifndef CKV_IO_SIZE
  480. #define CKV_IO_SIZE 1024
  481. #endif /* CKV_IO_SIZE */
  482.  
  483.     if (count > CKV_IO_SIZE)
  484.     count = CKV_IO_SIZE;
  485. #endif /* COMMENT */
  486.  
  487.     debug(F101,"txbufr 1 read","",count);
  488.     vms_status = sys$qiow(QIOW_EFN, ttychn, func|IO$M_TIMED, &wrk_iosb, 0, 0,
  489.               ttxbuf, count, 0, &trmmsk, 0, 0);
  490. /*
  491.  * Did something _really_ bad happen?
  492.  */
  493.     if (vms_status != SS$_NORMAL) {
  494.     debug(F101,"txbufr 1 serious error, status","",vms_status);
  495.     return(-2);
  496.     }
  497.  
  498.     debug(F101,"txbufr 1 size","",wrk_iosb.size);
  499.     debug(F101,"txbufr 1 iosb","",wrk_iosb.status);
  500.     debug(F110,"txbufr 1 ttxbuf",ttxbuf,0);
  501.  
  502. /*
  503.  * How about a hangup?
  504.  */
  505.     if (wrk_iosb.status == SS$_HANGUP) { /* Check for disconnection */
  506.     debug(F100,"txbufr 1 hangup","",0);
  507.     return(-2);
  508.     }
  509.  
  510. /*
  511.  * Did anything useful happen?
  512.  */
  513.     if(wrk_iosb.size > 0) {
  514.     ttxbn = wrk_iosb.size;        /* Set buffer count. */
  515.     ttxbn--;            /* Less one for the one we return */
  516.     return(ttxbuf[ttxbp++] & 0xff);    /* Return it, bump offset */
  517.     }
  518.  
  519. /*
  520.  * An unexpected status?
  521.  */
  522.     if (wrk_iosb.status != SS$_TIMEOUT) {
  523.     debug(F101, "txbufr 1 unexpected iosb status", "", wrk_iosb.status);
  524.     return(-2);            /* Call it a hangup */
  525.     }
  526.  
  527. /*
  528.  * If we didn't get any characters, then try a blocking, possibly timed,
  529.  * read for a single character. Since this routine will called again very
  530.  * soon, the first read with a zero timeout will have the rest of the user
  531.  * data in it. Thus, this isn't as inefficient as it first appears.
  532.  */
  533.     if (timo > 0) func |= IO$M_TIMED;
  534.     debug(F101,"txbufr 2 read","",count);
  535.     vms_status = sys$qiow(QIOW_EFN, ttychn, func, &wrk_iosb, 0, 0,
  536.               ttxbuf, 1, timo, &trmmsk, 0, 0);
  537. /*
  538.  * Did something _really_ bad happen?
  539.  */
  540.     if (vms_status != SS$_NORMAL) {
  541.     debug(F101,"txbufr 2 serious error, status","",vms_status);
  542.     return(-2);
  543.     }
  544.  
  545.     debug(F101,"txbufr 2 size","",wrk_iosb.size);
  546.     debug(F101,"txbufr 2 iosb","",wrk_iosb.status);
  547.     debug(F110,"txbufr 2 ttxbuf",ttxbuf,0);
  548.  
  549. /*
  550.  * How about a hangup?
  551.  */
  552.     if (wrk_iosb.status == SS$_HANGUP) { /* Check for disconnection */
  553.     debug(F100,"txbufr 2 hangup","",0);
  554.     return(-2);
  555.     }
  556.  
  557. /*
  558.  * Did anything useful happen?
  559.  */
  560.     if(wrk_iosb.size > 0) {
  561.     ttxbn = wrk_iosb.size;        /* Set buffer count. */
  562.     ttxbn--;            /* Less one for the one we return */
  563.     return(ttxbuf[ttxbp++] & 0xff);    /* Return it, bump offset */
  564.     }
  565.  
  566. /*
  567.  * An unexpected status?
  568.  */
  569.     if (wrk_iosb.status != SS$_TIMEOUT) {
  570.     debug(F101, "txbufr 2 unexpected iosb status", "", wrk_iosb.status);
  571.     return(-2);            /* Call it a hangup */
  572.     }
  573.  
  574. /*
  575.  * Otherwise it's a timeout
  576.  */
  577.     debug(F101, "txbufr 2 returning timeout", "", 0);
  578.     return(-1);
  579. }
  580.  
  581. /*  T T I N C  --  Read a character from the communication device  */
  582. /*
  583.   ttinc() maintains an internal buffer to minimize system calls.
  584.   Returns the next character, or -1 if there is a timeout, or -2
  585.   on communications disconnect.  Calls txbufr() to refill its buffer
  586.   when necessary.
  587. */
  588. int
  589. ttinc(timo) int timo; {
  590.     int x; unsigned char c;
  591.  
  592. #ifdef NETCONN
  593.     if (network)
  594.       return(netinc(timo));
  595. #endif /* NETCONN */
  596.  
  597.     debug(F101,"ttinc ttxbn","",ttxbn);
  598.     if (--ttxbn >= 0) {            /* Something in internal buffer? */
  599.     c = ttxbuf[ttxbp++];        /* Yes, return next character. */
  600.     debug(F101,"ttinc returns c","",c);
  601.     return(c & 0xff);
  602.     } else if ((x = txbufr(timo)) < 0) { /* No, fill buffer */
  603.     debug(F101,"ttinc timed out","",x); /* Pass along failure. */
  604.     return(x);
  605.     } else {                /* Success. */
  606.     debug(F101,"ttinc returns x","",x);
  607.     return(x & 0xff);        /* Return the character */
  608.     }
  609. }
  610.  
  611. /*  T T X I N  --  Get n bytes from tty input buffer  */
  612. /*
  613.   Call with n = number of bytes to get, buf = where to put them.
  614.  
  615.   This routine assumes that the given number of bytes is available
  616.   and will not return until they are gotten.  You should only call this
  617.   routine after calling ttchk to find out how many bytes are waiting to
  618.   to be read.
  619.  
  620.   Returns:
  621.   -1 on error, number of chars gotten on success.
  622. */
  623. int
  624. ttxin(n,buf) int n; CHAR *buf; {
  625.     int i, x;
  626.  
  627.     debug(F101,"ttxin","",n);
  628.  
  629. #ifdef NETCONN
  630.     if (network) {
  631.     for (i = 0; i < n; i++) {
  632.         if ((x = ttinc(0)) < 0) return(-1);
  633.         buf[i] = (char) x;
  634.     }
  635.     } else {
  636. #endif /* NETCONN */
  637. /* xx_inc() is a macro */
  638.     for (i = 0; i < n; i++) {
  639.         if ((x = xx_inc(0)) < 0) return(-1);
  640.         buf[i] = (char) x;
  641.     }
  642. #ifdef NETCONN
  643.     }
  644. #endif /* NETCONN */
  645.     buf[i] = NUL;
  646.     return(i);
  647. }
  648.  
  649. /*  T T F L U I  --  Flush communication device input buffer  */
  650.  
  651. int
  652. ttflui() {
  653.     int n;
  654.     debug(F100,"ttflui","",0);
  655. #ifdef NETCONN
  656.     if (network)
  657.       return(netflui());
  658. #endif /* NETCONN */
  659.  
  660.     ttxbn = ttxbp = 0;            /* Flush internal buffer *FIRST* */
  661.     if ((n = ttchk()) > 0) {
  662.     debug(F101,"ttflui count","",n);
  663. #ifdef NETCONN
  664.     if (network)
  665.       while ((n--) && ttinc(2) > -1) ; /* Don't worry, it's buffered. */
  666.     else
  667. #endif /* NETCONN */
  668.       while ((n--) && xx_inc(2) > -1) ; /* Don't worry, it's buffered. */
  669.     }
  670.     return(0);
  671. }
  672.  
  673. /*  T T C H K  --  Check how many bytes are waiting to be read */
  674. /*
  675.   Returns number of bytes waiting, or -1 if connection has been dropped.
  676.   The number of bytes waiting includes those in our internal buffer plus
  677.   those in VMS's internal input buffer.
  678. */
  679. int                    /* Check how many bytes are ready */
  680. ttchk() {                /* for reading from network */
  681.     static struct {
  682.     unsigned short count;
  683.     unsigned char first;
  684.     unsigned char reserved1;
  685.     long reserved2; } ttchk_struct;
  686.  
  687. #ifdef NETCONN
  688.     if (network)            /* If network connection active... */
  689.       return(nettchk());        /* Check real network. */
  690. #endif /* NETCONN */
  691.  
  692.     CHECK_ERR("ttchk: sys$qiow",
  693.     sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE|IO$M_TYPEAHDCNT, &wrk_iosb,
  694.          0, 0, &ttchk_struct, sizeof(ttchk_struct), 0, 0, 0, 0));
  695. #ifdef DEBUG
  696.     debug(F101,"ttchk count","",(int)ttchk_struct.count);
  697.     if (ttchk_struct.count)
  698.       debug(F101,"ttchk first","",(int)ttchk_struct.first);
  699. #endif /* DEBUG */
  700.     return(vms_status & 1 ? ttchk_struct.count + ttxbn : ttxbn);
  701. }
  702.  
  703. #ifdef CTRLC
  704. #undef CTRLC
  705. #endif /* CTRLC */
  706. #define CTRLC '\03'
  707.  
  708. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  709. /*
  710.   Reads up to "max" characters from the communication line, terminating on:
  711.  
  712.     (a) the packet length field if the "turn" argument is zero, or
  713.     (b) on the packet-end character (eol) if the "turn" argument is nonzero
  714.     (c) two Ctrl-C's in a row
  715.  
  716.   and returns the number of characters read upon success, or if "max" was
  717.   exceeded or the timeout interval expired before (a) or (b), returns -1.
  718.  
  719.   The characters that were input are copied into "dest" with their parity bits
  720.   stripped if parity was selected.  Returns the number of characters read.
  721.   Characters after the eol are available upon the next call to this function.
  722.  
  723.   Since this function has grown to have its fingers so deeply into the
  724.   protocol, it is slated for removal: rpack() will take care of everything.
  725. */
  726.  
  727. int
  728. #ifdef CK_ANSIC
  729. ttinl(CHAR *dest, int max, int timo, CHAR eol, CHAR start, int turn)
  730. #else
  731. ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest,eol,start;
  732. #endif /* CK_ANSIC */
  733. /* ttinl */ {
  734.     int x, y, c, i, j;
  735.     int ccn = 0;        /* Control C counter */
  736.     int flag;
  737.     int cc;
  738.     unsigned char *cp;
  739.     int pktlen = -1;
  740.     int lplen = 0;
  741.     int havelen = 0;
  742.  
  743.     debug(F101,"ttinl start","",start);
  744.     debug(F101,"ttinl turn","",turn);
  745.     i = j = flag = 0;
  746.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask. */
  747.     while (i < max) {
  748.     cc = network ? ttinc(timo) : xx_inc(timo); /* Read a byte */
  749.     if (cc < 0)            /* Check for error */
  750.       return(-1);
  751.     if (xfrcan && ((cc & 0x7f) == xfrchr)) { /* Check for cancellation */
  752.         if (++ccn >= xfrnum) {    /* If xfrnum in a row, bail out. */
  753.         fprintf(stderr,"^C...\r\n"); /* Echo Ctrl-C */
  754.         return(-2);
  755.         }
  756.     } else ccn = 0;            /* No cancel, so reset counter, */
  757.  
  758.     if ((flag == 0) && ((cc & 0x7f) == start)) {
  759.         debug(F100,"ttinl got start","",0);
  760.         flag = 1;            /* Got packet start. */
  761.     }
  762.     if (flag) {            /* If we're in a packet... */
  763.         dest[i++] = cc & ttpmsk;
  764.         if ((cc & 0x7f) == eol) { /* Stop at eol. */
  765.         debug(F101,"ttinl got eol, i","",i);
  766.         break;
  767.         }
  768.     }
  769. /*
  770.   If we have not been instructed to wait for a turnaround character, we
  771.   can go by the packet length field.  If turn != 0, we must wait for the
  772.   end of line (eol) character before returning.
  773. */
  774. #ifndef xunchar
  775. #define xunchar(ch) (((ch) - 32 ) & 0xFF )    /* Character to number */
  776. #endif /* xunchar */
  777.  
  778.     if (i == 2) {
  779.         pktlen = xunchar(dest[1]);
  780.         havelen = (pktlen > 1);
  781.         debug(F101,"ttinl length","",pktlen);
  782.     } else if (i == 5 && pktlen == 0) {
  783.         lplen = xunchar(dest[4]);
  784.     } else if (i == 6 && pktlen == 0) {
  785.         pktlen = lplen * 95 + xunchar(dest[5]) + 5;
  786.         havelen = 1;
  787.         debug(F101,"ttinl length","",pktlen);
  788.     }
  789.     if (havelen && !turn && (i > pktlen+1)) { /* Use length field */
  790.         debug(F101,"ttinl break on length","",i);
  791.         break;
  792.     }
  793.     }
  794.     dest[i] = '\0';            /* Terminate the string */
  795.     debug(F101,"ttinl loop done, i","",i);
  796.     debug(F101,"ttinl max","",max);
  797.     debug(F101,"ttinl dest[i-1]","",dest[i-1]);
  798.     debug(F101,"ttinl eol","",eol);
  799.  
  800.     if (i >= max) {
  801.     debug(F100,"ttinl buffer overflow","",0);
  802.     return(-1);    /* Overflowed dest buffer without getting eol */
  803.     }
  804.     x = i;                /* Size. */
  805.     debug(F111,"ttinl got packet",dest,x);
  806.  
  807.     debug(F101,"ttinl size","",x);    /* Log the size */
  808.     dest[x] = '\0';            /* Terminate with null */
  809.  
  810.     if (ttpflg++ == 0 && ttprty == 0) {    /* Check and adjust the parity. */
  811.         if ((ttprty = parchk(dest,start,x)) > 0) {
  812.         debug(F000,"ttinl parchk senses parity","",ttprty);
  813.         ttpmsk = 0x7f;
  814.         for (i = 0; i < x; i++)    /* Strip parity from this packet */
  815.           dest[i] &= 0x7f;
  816.     }
  817.     if (ttprty < 0) ttprty = 0;    /* Restore if parchk error */
  818.     }
  819.     return(x);                /* Return length */
  820. }
  821.  
  822. #endif /* TTXBUF */
  823.  
  824. SIGTYP (*saval)() = NULL;        /* For saving alarm handler */
  825.  
  826. VOID
  827. ttimoff() {                /* Turn off any timer interrupts */
  828.     alarm(0);
  829.     if (saval)
  830.       signal(SIGALRM,saval);
  831.     else
  832.       signal(SIGALRM,SIG_DFL);
  833.     saval = NULL;
  834. }
  835.  
  836. /*  P R I N T _ M S G  --  Log an error message from VMS  */
  837.  
  838. int
  839. print_msg(s) char *s; {
  840.     long int blen = 0;
  841.     char buf[PMSG_BUF_SIZE], msg[PMSG_MSG_SIZE];
  842.     struct dsc$descriptor_s b = {
  843.     PMSG_BUF_SIZE-1,
  844.     DSC$K_DTYPE_T,
  845.     DSC$K_CLASS_S,(char *)&buf
  846.     };
  847.  
  848.     if (!((vms_status = sys$getmsg(vms_status, &blen, &b, 0, 0)) & 1)) {
  849.     fprintf(stderr,"print_msg; sys$getmsg\n");
  850.     return(-1);
  851.     }
  852.     buf[blen] = '\0';
  853.     sprintf(msg, "%s: %s\n", s, buf);
  854.     debug(F100,s,"",0);
  855.     ermsg(msg);
  856.     return(0);
  857. }
  858.  
  859. /*  S Y S I N I T  --  System-dependent program initialization.  */
  860.  
  861. #ifndef DVI$_FULLDEVNAM
  862. #define DVI$_FULLDEVNAM 232
  863. #endif /* DVI$_FULLDEVNAM */
  864.  
  865. #ifndef DVI$_STS
  866. #define DVI$_STS 226
  867. #endif /* DVI$_STS */
  868.  
  869. int
  870. sysinit() {
  871.     extern int speed;
  872.     extern char ttname[];
  873.     extern char *ckzsys;
  874.     struct itmlst dviitm[] = {{64,DVI$_FULLDEVNAM,(char *)&lclnam,0},
  875.             {sizeof(conclass),DVI$_DEVCLASS,(char *)&conclass,0},
  876.                 {0,0,0,0}};
  877.  
  878.     static struct desblk {
  879.     long int *fl;            /* Forward link.  Used by VMS only */
  880.     void (*fncpnt)();        /* Function to call */
  881.     unsigned char argcnt;        /* Only one arg allowed */
  882.     unsigned char filler[3];    /* Filler.  Must be zero */
  883.     long int *sts;            /* Address of sts (written by VMS) */
  884.     } dclexh_ = {0,dcl_exit_h,1,{0,0,0},&dclexh_status};
  885.  
  886. #define GETCKXSYS
  887. /*
  888.   Get architecture and operating system name.
  889. */
  890. #ifdef GETCKXSYS
  891.  
  892. #if defined(__ALPHA)
  893.  
  894.     ckxsys = " OpenVMS AXP";
  895.  
  896. #elif !(defined(__VAX) || defined (VAX) || defined (__GNUC__))
  897. # error Unknown Hardware type, not VAX(tm) and not AXP (TM)
  898. #else /* VAX */
  899.  
  900. /* OK, we have a VAX so what is the name of the OS? */
  901.  
  902. #ifndef SYI$_ARCH_NAME    /* Should be in syidef.h but is not there yet */
  903. # define SYI$_ARCH_NAME 4454
  904. #endif /* SYI$_ARCH_NAME */
  905.  
  906.     struct iosb_t {
  907.     short int status;        /* System service status */
  908.     short int unused[3];
  909.     } iosb;
  910.  
  911.     struct itmlst_t {
  912.     short unsigned int buffer_len;    /* Buffer length */
  913.     short unsigned int item_code;    /* Item code */
  914.     char*buffer;            /* Where to write SYI info */
  915.     long unsigned int *ret_len;    /* Pointer to returned length */
  916.     long unsigned int mbz;        /* Must Be Zero */
  917.  
  918.     } itmlst;
  919.  
  920.     char arch_name[sizeof ("Alpha") - 1]; /* Architecture name */
  921.     long unsigned int ret_len;        /* Returned length */
  922. /*
  923.   $getsyi of "hw_arch" will fail prior to VMS 5.5.  This failure indicates that
  924.   the OS name is "VAX/VMS" (sic).  Use success or failure or $getsyi "hw_arch"
  925.   rather than the more straight forward $getsyi "node_swvers" because latter
  926.   is defined as four (4) characters and will get strange representing VMS
  927.   10.0.
  928. */
  929.  
  930. /*  Default -- Not strictly correct but traditional & familiar... */
  931.     ckxsys = " VAX/VMS";
  932.  
  933.     itmlst.buffer_len = sizeof (arch_name);
  934.     itmlst.item_code = SYI$_ARCH_NAME;
  935.     itmlst.buffer = arch_name;
  936.     itmlst.ret_len = &ret_len;
  937.     itmlst.mbz = 0;
  938.  
  939.     if ((sys$getsyiw (0, 0, 0,
  940.             &itmlst,
  941.             &iosb,
  942.             0, 0) & 1) == 1)
  943.     if ((iosb.status & 1) == 1)
  944.         ckxsys = " OpenVMS VAX";
  945.  
  946.     ckzsys = ckxsys;            /* Same deal for file module */
  947.  
  948. #endif /* OS Type */
  949. #endif /* GETCKXSYS */
  950.  
  951. /*
  952.  * Set up DCL Exit handler.  This allows us to reset terminal
  953.  * and any other modifications we have done.
  954.  */
  955.     debug(F101,"sysinit ttychn","",ttychn);
  956.     debug(F101,"sysinit conchn","",conchn);
  957.     if (!CHECK_ERR("sysinit: sys$dclexh",
  958.            sys$dclexh(&dclexh_))) {
  959.         debug(F100,"sysinit failed to declare exit handler","",0);
  960. #ifdef COMMENT
  961.     return(0);
  962. #endif /* COMMENT */
  963.     }
  964.     if (ttychn)                         /* if comms line already opened */
  965.       return(0);            /* (how could it be???) */
  966.  
  967.     if (!conchn) {            /* Get console channel */
  968.       struct dsc$descriptor_s devnam =
  969.         {sizeof(dftty)-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,dftty};
  970.       conchn = vms_assign_channel(&devnam);
  971.     }
  972.     congm();                /* Get and save its modes */
  973. /*
  974.  * Parse console terminal device name.
  975.  */
  976.     CHECK_ERR("sysinit: sys$getdviw",
  977.     sys$getdviw(0, conchn, 0, &dviitm, &wrk_iosb, 0, 0, 0));
  978.     debug(F111,"sysinit","lclnam",lclnam);
  979.  
  980.     if (!CHECK_ERR("sysinit: sys$qiow",
  981.         sys$qiow(QIOW_EFN, conchn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  982.                  &ccold, sizeof(ccold), 0, 0, 0, 0))) return(-1);
  983.  
  984.     speed = ttispd((unsigned char) wrk_iosb.size);
  985.     debug(F111,"sysinit speed",lclnam,speed);
  986.     strncpy(ttname,lclnam,80);
  987.  
  988.     /* Initialize descriptor */
  989.     tt_fulldevnam_d.dsc$b_dtype = DSC$K_DTYPE_T;
  990.     tt_fulldevnam_d.dsc$b_class = DSC$K_CLASS_S;
  991.  
  992.     debug(F100,"sysinit done","",0);
  993.     return(0);
  994. }
  995.  
  996. /*
  997.  * DCL Exit handler.  This is the cleanup handler for program.
  998.  * Any final cleanup (closing channels etc) should be done at this
  999.  * point.
  1000.  */
  1001. VOID
  1002. dcl_exit_h(sts) unsigned long int *sts; {
  1003.     syscleanup();
  1004.     return;
  1005. }
  1006.  
  1007. /*  S Y S C L E A NU P -- System-dependent program epilog.  */
  1008.  
  1009. int
  1010. syscleanup() {
  1011.     extern zclosf();
  1012.  
  1013.     ttclos(ttyfd);        /* Do the cleanup no matter what... */
  1014.     conres();            /* for the console also... */
  1015.     zclosf();            /* Close various files and kill child proc */
  1016.     printf("\r");
  1017.     return(0);
  1018. }
  1019.  
  1020. /*  T T O P E N  --  Open a tty for exclusive access.  */
  1021.  
  1022. /*  Returns 0 on success, -1 on failure.  */
  1023. /*
  1024.   If called with lcl < 0, sets value of lcl as follows:
  1025.   0: the terminal named by ttname is the job's controlling terminal.
  1026.   1: the terminal named by ttname is not the job's controlling terminal.
  1027.   But watch out: if a line is already open, or if requested line can't
  1028.   be opened, then lcl remains (and is returned as) -1.
  1029. */
  1030. int
  1031. ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
  1032.     extern int speed;
  1033.     int s;
  1034.     unsigned long int devchar, devclass, devsts;
  1035. /*    char dvibuf[65]; */
  1036.     struct dsc$descriptor_s devnam = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  1037.     struct itmlst dviitm[] = {{64,DVI$_FULLDEVNAM,(char *)&tt_fulldevnam,0},
  1038.             {sizeof(devchar),DVI$_DEVCHAR,(char *)&devchar,0},
  1039.             {sizeof(devclass),DVI$_DEVCLASS,(char *)&devclass,0},
  1040.             {sizeof(devsts),DVI$_STS,(char *)&devsts,0},
  1041.             {0,0,0,0}};
  1042.  
  1043. #ifdef NETCONN
  1044.     if (network && ttyfd > -1) {    /* if device already opened */
  1045.         if (strncmp(ttname,ttnmsv,80))    /* are new & old names equal? */
  1046.           ttclos(ttyfd);        /* no, close old ttname, open new */
  1047.         else                 /* else same, ignore this call, */
  1048.       return(0);            /* and return. */
  1049.     }
  1050.     if (modem < 0) {            /* modem < 0 = special code for net */
  1051.     int x;
  1052.     ttmdm = modem;
  1053.     modem = -modem;            /* Positive network type number */
  1054.     debug(F111,"ttopen net",ttname,modem);
  1055.     x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
  1056.     if (x > -1) {
  1057.         strncpy(ttnmsv,ttname,DEVNAMLEN);
  1058.         network = 1;
  1059.         x = tn_ini();        /* Initialize telnet protocol. */
  1060.         ttnet = modem;
  1061.     } else network = 0;
  1062.         return(x);
  1063.     }
  1064. #endif /* NETCONN */
  1065.  
  1066.     if (ttychn) return(0);        /* Close channel if open */
  1067.  
  1068.     devnam.dsc$w_length  = strlen(ttname);
  1069.     devnam.dsc$a_pointer = ttname;
  1070.     sys$getdviw(0, 0, &devnam, &dviitm, &wrk_iosb, 0, 0, 0);
  1071.     tt_fulldevnam[65] = '\0';        /* Make sure it has an end.... */
  1072.  
  1073.     if (devclass != DC$_TERM) {        /* Is it a terminal? */
  1074.     fprintf(stderr,
  1075.         "%%CKERMIT-W-NOTTERM, %s is not a terminal\n",ttname);
  1076.     return(-1);
  1077.     }
  1078.     if (!(devchar & DEV$M_AVL)) {    /* Is it available? */
  1079.     fprintf(stderr,
  1080.         "%%CKERMIT-W-NOTAVAL, %s is not available\n",tt_fulldevnam);
  1081.     return(-5);
  1082.     }
  1083.     if (!(devsts & UCB$M_ONLINE)) {    /* Is it online? */
  1084.     fprintf(stderr,
  1085.         "%%CKERMIT-W-OFFLINE, %s is not online\n",tt_fulldevnam);
  1086.     return(-5);
  1087.     }
  1088.     ttmdm = modem;            /* Make this available to other fns */
  1089.     xlocal = *lcl;            /* Make this available to other fns */
  1090.  
  1091. /*
  1092.  *  Set up the tt_fulldevnam_d descriptor for use by ttclos() later.
  1093.  */
  1094.     tt_fulldevnam_d.dsc$w_length  = strlen(tt_fulldevnam);
  1095.     tt_fulldevnam_d.dsc$a_pointer = tt_fulldevnam;
  1096.  
  1097. /*
  1098.  *  Try to allocate the device.  This is necessary to avoid just assigning
  1099.  *  a channel with SHARE privilege and interfering with someone else using
  1100.  *  the terminal.
  1101.  */
  1102.     if (!CHECK_ERR("vms_allocate_device: sys$alloc",
  1103.     sys$alloc(&tt_fulldevnam_d, 0, 0, 0, 0))) return(-1);
  1104.  
  1105.     ttychn = vms_assign_channel(&devnam); /* Get a channel for it. */
  1106.  
  1107.     debug(F111,"ttopen","modem",modem);
  1108.     debug(F101," ttychn","",ttychn);
  1109.  
  1110.     if (!ttychn) return(-1);        /* If couldn't open, fail. */
  1111. /*
  1112.  * Check for maximum size of QIO, so as to not get the dreaded quota exceeded
  1113.  * status returned.  When doing a QIO that has a larger buffer than
  1114.  * MAXBUF, exceeded quota wil be returned.
  1115.  *
  1116.  * Example: MAXBUF = 2048, QIO = 1936, overhead is 112 will succeed.
  1117.  *        QIO of 1937 will fail.
  1118.  *
  1119.  * This can change for different versions of VMS.
  1120.  */
  1121.     qio_maxbuf_size = get_qio_maxbuf_size(ttychn);
  1122.  
  1123.     strncpy(ttname,tt_fulldevnam,80);    /* Copy true name back to main pgm  */
  1124.  
  1125.     strcpy(ttnmsv,ttname);        /* Open, keep copy of name locally. */
  1126.     ttxbn = ttxbp = 0;            /* Initialize input buffer */
  1127.  
  1128. /* Caller wants us to figure out if line is controlling tty */
  1129.  
  1130.     debug(F111,"ttopen ok",ttname,*lcl);
  1131.     if (*lcl < 0) {
  1132.     if (conclass == DC$_TERM)
  1133.       xlocal = (strncmp(ttname,lclnam,80) == 0) ? 0 : 1;
  1134.     else
  1135.       xlocal = 1;             /* If not a term, then we must be local */
  1136.     debug(F111,"ttyname",lclnam,xlocal);
  1137.     }
  1138.     if (!CHECK_ERR("ttopen: sys$qiow",
  1139.     sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  1140.          &ttold, sizeof(ttold), 0, 0, 0, 0))) return(-1);
  1141.  
  1142.     speed = ttispd((unsigned char) wrk_iosb.size);
  1143.  
  1144. /* Got the line, now set the desired value for local. */
  1145.  
  1146.     if (*lcl) *lcl = xlocal;
  1147.  
  1148.     tttvt = ttold;
  1149.     ttraw = ttold;
  1150.     debug(F101," lcl","",*lcl);
  1151.     return(0);
  1152. }
  1153.  
  1154. #ifdef COMMENT
  1155. /*
  1156.   Old version.
  1157. */
  1158. unsigned long int
  1159. vms_assign_channel(ttname) char *ttname;  {
  1160.     unsigned int channel = 0;
  1161.     struct dsc$descriptor_s d = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  1162.  
  1163.     d.dsc$w_length  = strlen(ttname);
  1164.     d.dsc$a_pointer = ttname;
  1165.     if (!CHECK_ERR("vms_assign_channel: sys$assign",
  1166.     sys$assign(&d, &channel, 0, 0))) return(0);
  1167.     return(channel);
  1168. }
  1169. #else
  1170. /*
  1171.   New version from Hunter Goatley.
  1172. */
  1173. unsigned long int
  1174. vms_assign_channel(ttname) char *ttname;  {
  1175.     unsigned int channel = 0;
  1176. /*
  1177.     struct dsc$descriptor_s d = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  1178.     d.dsc$w_length  = strlen(ttname);
  1179.     d.dsc$a_pointer = ttname;
  1180. */
  1181.     if (!CHECK_ERR("vms_assign_channel: sys$assign",
  1182.     sys$assign(ttname, &channel, 0, 0))) return(0);
  1183.     return(channel);
  1184. }
  1185. #endif /* COMMENT */
  1186.  
  1187. /*  T T C L O S  --  Close the communication device.  */
  1188.  
  1189. int
  1190. ttclos(ttyfd) int ttyfd; {
  1191. #ifdef NETCONN
  1192.     if (network) {            /* Network connection. */
  1193.     debug(F100,"ttclos closing net","",0);
  1194.     netclos();            /* Close it. */
  1195.     network = 0;
  1196.     return(0);
  1197.     }
  1198. #endif /* NETCONN */
  1199.     if (!ttychn) return(0);        /* Wasn't open. */
  1200. /*
  1201.   Observations indicate that it can take 20-30 seconds for DTR to drop
  1202.   after closing the device.  Perhaps a call to tthang() should go here.
  1203. */
  1204.     ttres();                /* Reset modes. */
  1205.  
  1206. /*
  1207.   Assume it's a LAT device and try to do a LAT disconnect on it.
  1208.   If it fails, then it's not a LAT device and no harm is done.
  1209. */
  1210. #ifdef IO$M_LT_DISCON
  1211.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_TTY_PORT|IO$M_LT_DISCON,
  1212.               &wrk_iosb, 0, 0, 0, 0, 0, 0, 0, 0);
  1213.     debug(F101, "ttclos LAT disconnect, status", "", vms_status);
  1214.     debug(F101, "ttclos LAT disconnect, iosb", "", wrk_iosb.status);
  1215. #else
  1216.     debug(F100, "ttclos LAT disconnect not supported", "", 0);
  1217. #endif /* IO$M_LT_DISCON */
  1218.     if (!CHECK_ERR("ttclos: sys$dassgn",
  1219.     sys$dassgn(ttychn))) return(-1);
  1220.     sys$dalloc (&tt_fulldevnam_d, 0);    /* Deallocate the device */
  1221.     ttychn = 0;                /* Mark it as closed. */
  1222.     return(0);
  1223. }
  1224.  
  1225.  
  1226. /*  T T R E S  --  Restore terminal to its original modes.  */
  1227.  
  1228. int
  1229. ttres() {                /* Restore the tty to normal. */
  1230. #ifdef NETCONN
  1231.     if (network) return (0);        /* Network connection, do nothing */
  1232. #endif /* NETCONN */
  1233.  
  1234.     if (!ttychn) return(-1);        /* Not open. */
  1235.  
  1236.     tt_cancel();            /* Cancel outstanding I/O */
  1237.     msleep(250);            /* Wait for pending i/o to finish. */
  1238.     debug(F101,"ttres, ttychn","",ttychn);
  1239.     if (!CHECK_ERR("ttres: sys$qiow",
  1240.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1241.              &ttold, sizeof(ttold), 0, 0, 0, 0))) return(-1);
  1242.     return(0);
  1243. }
  1244.  
  1245. /*  T T B I N  --  Code shared by ttpkt() and ttvt()  */
  1246. /*
  1247.   Puts communication device in "binary" mode.  In VMS there's no distinction
  1248.   between device modes for terminal connection, packet operation, and dialing.
  1249. */
  1250. static int
  1251. ttbin(speed, xflow, xparity) int speed, xflow, xparity; {
  1252.     int s;
  1253.     extern int flow;            /* Global flow control variable */
  1254.  
  1255. #ifdef NETCONN
  1256.     if (network) return(0);        /* Nothing to do on net connections */
  1257. #endif /* NETCONN */
  1258.     if (!ttychn) return(-1);        /* Not open. */
  1259.  
  1260.     ttspeed = speed;            /* Keep local copies of arguments */
  1261.     if (xflow != FLO_DIAL && ttflow != FLO_DIAX)
  1262.       ttflow = xflow;            /* for other CKVTIO routines. */
  1263.     if (xparity > -1) {
  1264.     ttprty  = xparity;
  1265.     ttpflg  = 0;            /* Parity not sensed yet */
  1266.     ttpmsk  = ttprty ? 0177 : 0377;    /* Parity stripping mask */
  1267.     debug(F101,"ttbin ttprty","",ttprty);
  1268.     }
  1269.     ttraw = ttold;            /* Get a fresh copy of this */
  1270.  
  1271.     if ((s = ttsspd(speed/10)) < 0)    /* Get internal speed code */
  1272.       s = 0;
  1273.  
  1274. /*
  1275.  * Log original terminal settings for debugging purposes
  1276.  */
  1277.     debug(F101, "original ttraw.basic", "", ttraw.basic);
  1278.     debug(F101, "original ttraw.extended", "", ttraw.extended);
  1279.  
  1280. /*
  1281.  * Settings based on call parameters flow-control and parity...
  1282.  * NOTE: we are using the GLOBAL copy of flow, not our parameter here.
  1283.  * This is because the parameter might be FLO_DIAL or FLO_DIALX, which
  1284.  * is not flow control at all.
  1285.  */
  1286.     if (flow == FLO_XONX) {                /* FLOW = XON/XOFF */
  1287.     ttraw.basic |=  (TT$M_HOSTSYNC|TT$M_TTSYNC);
  1288.     } else if (flow == FLO_NONE) {            /* FLOW = NONE */
  1289.     ttraw.basic &= ~(TT$M_HOSTSYNC|TT$M_TTSYNC);
  1290.     } else if (flow == FLO_KEEP) {            /* FLOW = KEEP */
  1291. /*
  1292.  * Put flow-control paramaters back the way we found them when
  1293.  * the device was first opened.
  1294.  */
  1295.     if (ttold.basic & TT$M_HOSTSYNC)
  1296.       ttraw.basic |= TT$M_HOSTSYNC;
  1297.     else
  1298.       ttraw.basic &= ~TT$M_HOSTSYNC;
  1299.     if (ttold.basic & TT$M_TTSYNC)
  1300.       ttraw.basic |= TT$M_TTSYNC;
  1301.     else
  1302.       ttraw.basic &= ~TT$M_TTSYNC;
  1303. /*
  1304.   NOTE: any other FLOW-related parameters should also be handled here.
  1305.   READSYNC?  And especially if DEC ever implements RTS/CTS or other
  1306.   hardware flow control for (Open)VMS.
  1307. */
  1308.     }
  1309.  
  1310. /*
  1311.   EIGHTBIT setting depends on GLOBAL copy of parity variable, not our
  1312.   parameter.
  1313. */
  1314.     if (parity == 0)
  1315.       ttraw.basic  |= TT$M_EIGHTBIT;    /* Allow 8-bit data if no parity */
  1316.     else                /* Otherwise */
  1317.       ttraw.basic  &= ~TT$M_EIGHTBIT;    /* 7-bit data. */
  1318.  
  1319.     ttraw.basic |= TT$M_NOECHO;        /* Turn off echo */
  1320.     ttraw.basic |= TT$M_NOBRDCST;    /* Turn off broadcasts */
  1321.     ttraw.basic &= ~TT$M_NOTYPEAHD;    /* Enable type-ahead */
  1322.     ttraw.basic &= ~TT$M_ESCAPE;    /* Disable escape-seq processing */
  1323.     ttraw.extended &= ~TT2$M_LOCALECHO;    /* Disable local echo */
  1324.     ttraw.extended |= TT2$M_PASTHRU;    /* Enable pass-through mode */
  1325.     ttraw.extended |= TT2$M_ALTYPEAHD;    /* Use big type-ahead buffers */
  1326.  
  1327. /*
  1328.  * Report what we did so we can check for problems
  1329.  */
  1330.     debug(F101, "ttraw.basic", "", ttraw.basic);
  1331.     debug(F101, "ttraw.extended", "", ttraw.extended);
  1332.  
  1333.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1334.              &ttraw, sizeof(ttraw), s, 0, 0, 0);
  1335.  
  1336.     if (vms_status != SS$_NORMAL) {    /* Error queuing request */
  1337.     print_msg("ttbin: sys$qiow");
  1338.     return(-1);
  1339.     }
  1340.     if (wrk_iosb.status != SS$_NORMAL) { /* Error executing request */
  1341.     vms_status = wrk_iosb.status;
  1342.     print_msg("ttbin: sys$qiow(iosb)");
  1343.     return(-1);
  1344.     }
  1345.     debug(F100,"ttbin ok","",0);
  1346.     return(0);                /* All OK */
  1347. }
  1348.  
  1349. /*  T T P K T  --  Condition the communication device for packets. */
  1350.  
  1351. #ifdef COMMENT
  1352. #define DIALING    4        /* Flags (via flow) for modem handling */
  1353. #define CONNECT 5        /* NOT YET IMPLEMENTED IN VMS! */
  1354. #endif /* COMMENT */
  1355.  
  1356. /*  Returns 0 on success, -1 on failure.  */
  1357.  
  1358. int
  1359. ttpkt(speed,flow,parity) long speed; int flow, parity; {
  1360.     int x;
  1361.     debug(F101,"ttpkt flow","",flow);
  1362.     x = ttbin(speed,flow,parity);    /* Put device in binary mode */
  1363.     debug(F101,"ttpkt ttbin","",x);
  1364.     return(x);
  1365. }
  1366.  
  1367. /*  T T V T  --  Condition communication device terminal connection. */
  1368.  
  1369. int
  1370. ttvt(speed,flow) long speed; int flow; {
  1371.     int x;
  1372.     debug(F101,"ttvt flow","",flow);
  1373.     if ((x = ttbin(speed,flow,-1)) > -1) /* Put device in binary mode */
  1374.       tvtflg = 1;
  1375.     debug(F101,"ttvt ttbin","",x);
  1376.     return(x);
  1377. }
  1378.  
  1379. /* T T I S P D  -- Return binary baud rate for internal coded speed */
  1380.  
  1381. int
  1382. ttispd(ispeed) unsigned char ispeed; {
  1383.     int s;
  1384.  
  1385. #ifdef NETCONN
  1386.     if (network) return(-1);
  1387. #endif /* NETCONN */
  1388.  
  1389. /* When the line is set, grab the line speed  and save it */
  1390.  
  1391.     for (s = 0;  ttspeeds[s].dec &&
  1392.     (ttspeeds[s].dec != ispeed);  s++)
  1393.         ;
  1394.  
  1395. /* If speed is zero, then no match.  Set speed to -1 so it is undefined */
  1396.  
  1397.     return(ttspeeds[s].line ? (int) ttspeeds[s].line * 10 : -1);
  1398.  
  1399. }
  1400.  
  1401.  
  1402. /*  T T S S P D  --  Return the internal baud rate code for 'speed'.  */
  1403.  
  1404. int
  1405. ttsspd(cps) int cps; {
  1406.     int s;
  1407.     char msg[50];
  1408.  
  1409. #ifdef    NETCONN
  1410.     if (network) return(0);
  1411. #endif    /* NETCONN */
  1412.  
  1413.     if (cps <= 0)            /* 026 Unknown cps fails */
  1414.     return (-1);
  1415.     for (s = 0;  ttspeeds[s].line && (ttspeeds[s].line != cps);  s++) ;
  1416.     if (ttspeeds[s].line)
  1417.     return(ttspeeds[s].dec);
  1418.     else {
  1419.     sprintf(msg,"Unsupported line speed - %d\n",cps*10);
  1420.     ermsg(msg);
  1421.     ermsg("Current speed not changed\n");
  1422.     return(-1);
  1423.     }
  1424. }
  1425.  
  1426.  
  1427. /* Interrupt Functions */
  1428.  
  1429.  
  1430. /*  C O N I N T  --  Console Interrupt setter  */
  1431.  
  1432. static int (*cctrap)();
  1433.  
  1434. VOID
  1435. #ifdef CK_ANSIC
  1436. conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
  1437. #else
  1438. conint(f,s) int (*f)(int), (*s)(int);
  1439. #endif /* CK_ANSIC */
  1440. /* conint */ {                /* Set an interrupt trap. */
  1441.  
  1442.     cctrap = f;                /* Make a global copy */
  1443.     debug(F101,"conint batch","",batch);
  1444.     if (batch) return;            /* Ignore signals in background. */
  1445.  
  1446. /* check if invoked in background -- if so signals set to be ignored */
  1447.  
  1448. #ifdef COMMENT
  1449. /* This is interfered with by connoi() */
  1450.     if (signal(SIGINT,SIG_IGN) == SIG_IGN) {
  1451.     debug(F100,"conint signal diagnoses batch","",0);
  1452.     batch = 1;            /* means running in background */
  1453.     return;
  1454.     }
  1455. #else
  1456.     if (!isatty(0)) {
  1457.     debug(F100,"conint isatty diagnoses batch","",0);
  1458.     batch = backgrd = 1;        /*   means running in background */
  1459.     return;
  1460.     }
  1461. #endif /* COMMENT */
  1462.  
  1463.     signal(SIGINT,f);            /* Function to trap to. */
  1464.     conif = 1;                /* Flag console interrupts on. */
  1465. }
  1466.  
  1467. /*  C O N N O I  --  Reset console terminal interrupts */
  1468.  
  1469. VOID
  1470. connoi() {                /* Console-no-interrupts */
  1471.  
  1472.     if (batch) return;            /* must ignore signals in bkgrd */
  1473.  
  1474. #ifdef COMMENT
  1475. /* wrong... */
  1476.     signal(SIGINT,SIG_DFL);
  1477. #else
  1478. /* right?.. */
  1479.     signal(SIGINT,SIG_IGN);
  1480. #endif /* COMMENT */
  1481.     conif = 0;
  1482. }
  1483.  
  1484. /*  T T O L  --  Similar to "ttinl", but for writing.  */
  1485. /*
  1486.  * This probably should be buffered with a flush command added.
  1487.  */
  1488.  
  1489. #ifndef IO$M_BREAKTHRU
  1490. #define IO$M_BREAKTHRU    0x0200
  1491. #endif /* IO$M_BREAKTHRU */
  1492.  
  1493. int
  1494. ttol(s,n) int n; CHAR *s; {
  1495.     int x;
  1496.  
  1497. #ifdef NETCONN
  1498.     debug(F101,"ttol network","",network);
  1499.     if (network) {
  1500.     x = nettol(s,n);        /* Call network package. */
  1501.     } else {
  1502. #endif /* NETCONN */
  1503.     debug(F101,"ttol ttychn","",ttychn);
  1504.     if (!ttychn) return(-1);        /* Not open. */
  1505.     if (CHECK_ERR("ttol: sys$qiow",
  1506.               sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  1507.                    &wrk_iosb, 0, 0, s, n, 0, 0, 0, 0)))
  1508.       x = n;            /* was x = 0 */
  1509.     else x = -1;
  1510. #ifdef NETCONN
  1511.     }
  1512. #endif /* NETCONN */
  1513.     debug(F111,"ttol",s,n);
  1514.     if (x < 0) debug(F101,"ttol failed","",x);
  1515.     return(x);
  1516. }
  1517.  
  1518. /*  T T O C  --  Output a character to the communication line  */
  1519.  
  1520. int
  1521. #ifdef CK_ANSIC
  1522. ttoc(char c)
  1523. #else
  1524. ttoc(c) char c;
  1525. #endif    /* CK_ANSIC */
  1526. /* ttoc */ {
  1527. #ifdef NETCONN
  1528.     if (network) {
  1529.     return(nettoc(c));
  1530.     } else {
  1531. #endif /* NETCONN */
  1532.     debug(F101,"ttoc char","",c);
  1533.     if (!ttychn) {
  1534.         debug(F100,"ttoc ttychn not open","",0);
  1535.         return(-1);            /* Not open. */
  1536.     }    
  1537.     if (CHECK_ERR("ttoc: sys$qiow",
  1538.               sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  1539.                    &wrk_iosb, 0, 0, &c, 1, 0, 0, 0, 0)))
  1540.       return(0);
  1541. #ifdef NETCONN
  1542.     }
  1543. #endif /* NETCONN */
  1544.     return(-1);
  1545. }
  1546.  
  1547. /*  T T _ C A N C E L  --  Cancel i/o on tty channel if not complete  */
  1548.  
  1549. VOID
  1550. tt_cancel() {
  1551.     int mask;
  1552. #ifdef NETCONN
  1553.     if (network) return;
  1554. #endif /* NETCONN */
  1555.     CHECK_ERR("tt_cancel: sys$cancel",sys$cancel(ttychn));
  1556.     tt_queued = 0;
  1557. }
  1558.  
  1559. /*  C O N _ C A N C E L  --  Cancel i/o on console channel if not complete  */
  1560.  
  1561. VOID
  1562. con_cancel() {
  1563.     int mask;
  1564.  
  1565.     CHECK_ERR("con_cancel: sys$cancel",sys$cancel(conchn));
  1566.     con_queued = 0;
  1567. }
  1568.  
  1569. /*  S N D B R K  --  Send a BREAK signal of the given length.  */
  1570.  
  1571. int
  1572. sndbrk(msec) int msec; {
  1573.     int long x = 0;
  1574.     int brklen;
  1575.     struct iosb_struct  tmp_ttiosb;
  1576.     struct tt_mode ttchr;
  1577. #ifndef TT$M_BREAK            /* For old VMS with no BREAK... */
  1578. /*
  1579.   Note: 110 is used instead of 50, because 50 is not supported by all
  1580.   VAX serial port controllers.
  1581. */
  1582. #define BRKSPD = 110            /* Speed for simulating BREAK */
  1583. #define BRKSYM = TT$C_BAUD_110;        /* VMS symbol for this speed */
  1584. #endif /* TT$M_BREAK */
  1585.  
  1586. #ifdef NETCONN
  1587.     if (network)             /* Send network BREAK */
  1588.       return(netbreak());        /* Length doesn't matter */
  1589. #endif /* NETCONN */
  1590.  
  1591.     if (!ttychn) return(-1);        /* SET LINE not done. */
  1592.     debug(F101,"sndbrk msec","",msec);
  1593.  
  1594.     tt_cancel();            /* Cancel I/O */
  1595.  
  1596. #ifndef TT$M_BREAK            /* VMS doesn't have BREAK function */
  1597.  
  1598. /* Send the right number of NULs at BREAK-simulation speed... */
  1599.  
  1600.     brklen = ( BRKSPD * 1000 ) / ( msec * 10 ); /* Calculate number of chars */
  1601.     if (brklen > sizeof(brkarray)) brklen = sizeof(brkarray);
  1602.     debug(F101,"sndbrk speed","",BRKSPD);
  1603.     debug(F101,"sndbrk brklen","",brklen);
  1604.     if (!CHECK_ERR("ttsndb: SENSEMODE",
  1605.     sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  1606.         &ttchr, sizeof(ttchr), 0, 0, 0, 0))) return(-1);
  1607.     if (!CHECK_ERR("ttsndb: SETMODE(1)",
  1608.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &tmp_ttiosb, 0, 0,
  1609.         &ttchr, sizeof(ttchr), BRKSYM, 0, 0, 0))) return(-1);
  1610.     if (!CHECK_ERR("ttsndb: writing nulls",
  1611.     sys$qiow(QIOW_EFN, ttychn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &tmp_ttiosb,
  1612.          0, 0, (char *) brkarray, brklen, 0, 0, 0, 0))) return(-1);
  1613.     if (!CHECK_ERR("ttsndb: SETMODE(2)",
  1614.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &tmp_ttiosb, 0, 0,
  1615.         &ttchr, sizeof(ttchr), wrk_iosb.size, 0, 0, 0))) return(-1);
  1616. #else
  1617.     if (!CHECK_ERR("ttsndb: SENSEMODE",
  1618.     sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  1619.         &ttchr, sizeof(ttchr), 0, 0, 0, 0))) return(-1);
  1620.     x = TT$M_BREAK;            /* Break signal on */
  1621.     if (!CHECK_ERR("ttsndb: SETMODE(1)",
  1622.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1623.         &ttchr, sizeof(ttchr), 0, 0, x, 0))) return(-1);
  1624.     msleep(msec);            /* Sleep requested amount of time */
  1625.     x = 0;                /* Break signal off */
  1626.     if (!CHECK_ERR("ttsndb: SETMODE(2)",
  1627.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1628.         &ttchr, sizeof(ttchr), 0, 0, x, 0))) return(-1);
  1629. #endif /* TT$M_BREAK */
  1630.     return(0);
  1631. }
  1632.  
  1633. /*  T T S N D B  --  Send a BREAK signal  */
  1634.  
  1635. int
  1636. ttsndb() {
  1637.     return(sndbrk(275));
  1638. }
  1639.  
  1640. /*  T T S N D L B  --  Send a Long BREAK signal  */
  1641.  
  1642. int
  1643. ttsndlb() {
  1644.     return(sndbrk(1500));
  1645. }
  1646.  
  1647. /*  T T H A N G  --  Hang up the communications line  */
  1648. /*
  1649.   Warning: As written, this function DOES NOT WORK on terminal server
  1650.   ports.  This is a shortcoming of VMS, confirmed by the Digital Diagnostic
  1651.   Center (or whatever DDC stands for).  Someone should add code here to test
  1652.   if the ttychn device is not a real terminal, and if so to handle it some
  1653.   other way, like set the speed to zero for a sec, or close and reopen the
  1654.   device.
  1655. */
  1656. int
  1657. tthang() {
  1658.     if (!xlocal) return(0);        /* Only on local connections. */
  1659.  
  1660. #ifdef NETCONN
  1661.     if (network) {            /* Network connection. */
  1662.     int x;
  1663.     if (netclos() < 0) return(-1);    /* Close it */
  1664.         tvtflg = 0;
  1665.         x = 1;
  1666.     netopen(ttnmsv, &x, ttmdm);    /* Open it again */
  1667.         return(1);
  1668.     }
  1669. #endif /* NETCONN */
  1670.  
  1671.     if (!ttychn) return(0);        /* Not open. */
  1672.  
  1673.     tt_cancel();            /* Cancel pending i/o. */
  1674. /*
  1675.   This is NOT listed in the VMS Terminal Driver as one of the functions
  1676.   that does NOT work with LAT devices.
  1677. */
  1678.     debug(F101,"tthang 1","",gtimer());
  1679.     if (!CHECK_ERR("tthang: sys$qiow",
  1680.     sys$qiow(QIOW_EFN, ttychn, IO$_SETMODE|IO$M_HANGUP, &wrk_iosb, 0, 0,
  1681.         0, 0, 0, 0, 0, 0))) return(-1);
  1682. /*
  1683.   The following 3-second sleep is required because the sys$qiow() returns
  1684.   immediately, about 2.5 seconds before VMS brings DTR back up.  Without this
  1685.   sleep(), DIAL does not work at all if DIAL HANGUP is ON, and, worse,
  1686.   subsequent operations on the device can hang the Kermit process
  1687.   uninterruptibly.
  1688. */
  1689.     sleep(3);
  1690.     debug(F101,"tthang 2","",gtimer());
  1691.     return(1);
  1692. }
  1693.  
  1694. /*  M S L E E P  --  Millisecond version of sleep().  */
  1695.  
  1696. /*
  1697.  Handles intervals up to about 7 minutes (2**32 / 10**7 seconds)
  1698. */
  1699. int
  1700. msleep(m) int m; {
  1701.  
  1702.     struct time_struct {
  1703.     long int hi, lo;
  1704.     } t;
  1705.  
  1706.     if (m <= 0) return(0);
  1707.     t.hi = -10000 * m;  /*  Time in 100-nanosecond units  */
  1708.     t.lo = -1;
  1709.     if (!CHECK_ERR("msleep: sys$schdwk",
  1710.     sys$schdwk(0, 0, &t, 0))) return(-1);
  1711.     sys$hiber();
  1712.     debug(F101,"msleep ok","",m);
  1713.     return(0);
  1714. }
  1715.  
  1716. /*  R T I M E R --  Reset elapsed time counter  */
  1717.  
  1718. VOID
  1719. rtimer() {
  1720.     tcount = time( (long *) 0);
  1721. }
  1722.  
  1723.  
  1724. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  1725.  
  1726. int
  1727. gtimer() {
  1728.     int x;
  1729.     x = (int) (time( (long *) 0 ) - tcount);
  1730.     return( (x < 0) ? 0 : x );
  1731. }
  1732.  
  1733. /*  Z T I M E  --  Return date/time string  */
  1734.  
  1735. VOID
  1736. ztime(s) char **s; {
  1737.     static long clock;
  1738. #ifdef COMMENT
  1739. #ifdef bogus
  1740.     static char time_string[24];
  1741.     struct dsc$descriptor_s t =
  1742.     {sizeof(time_string)-1,DSC$K_DTYPE_T,DSC$K_CLASS_S,&time_string};
  1743.  
  1744.     if (!CHECK_ERR("ztime: sys$asctim",
  1745.     sys$asctim(0, &t, 0, 0))) return(-1);
  1746.     time_string[t.dsc$w_length] = '\0';
  1747.     *s = &time_string;
  1748. #else
  1749.     char *asctime();
  1750.     struct tm *tp;
  1751.  
  1752.     time(&clock);
  1753.     tp = localtime(&clock);
  1754.     *s = asctime(tp);
  1755. #endif /* bogus */
  1756. #else /* not COMMENT */
  1757. /*
  1758.  Apparently ctime() is available in old C libraries, even though asctime()
  1759.  is not.  Let's use the same method for all versions.
  1760. */
  1761.     time(&clock);
  1762.     *s = ctime(&clock);
  1763. #endif /* COMMENT */
  1764. }
  1765.  
  1766. /*  C O N G M  --  Get console terminal modes.  */
  1767.  
  1768. /*
  1769.  Saves current console mode, and establishes variables for switching between
  1770.  current (presumably normal) mode and other modes.
  1771. */
  1772. int
  1773. congm() {
  1774.     char s[] = "SYS$INPUT:";
  1775.     struct itmlst dviitm[] = { {4,DVI$_DEVCLASS,(char *)&dviitm[0].adr,0},
  1776.             {0,0,0,0}};
  1777.     struct dsc$descriptor_s
  1778.     r = {sizeof(s),DSC$K_DTYPE_T,DSC$K_CLASS_S,(char *)&s};
  1779.  
  1780.     debug(F101,"congm cgmf","",cgmf);
  1781.     if (cgmf) return(-1);        /* If called already, then nop */
  1782.  
  1783.     if (!CHECK_ERR("congm: sys$getdviw",
  1784.     sys$getdviw(0, 0, &r, &dviitm, &wrk_iosb, 0, 0, 0))) return(-1);
  1785.     debug(F101, "congm: devclass", "", (unsigned long int) dviitm[0].adr);
  1786.     if ((unsigned long int) dviitm[0].adr != DC$_TERM)
  1787.     batch = backgrd = 1;
  1788.     else {
  1789.         debug(F101, "congm: conchn", "", conchn);
  1790.     if (conchn == 0 && (conchn = vms_assign_channel("SYS$INPUT:")) == 0)
  1791.         return(-1);
  1792.         if (!CHECK_ERR("congm: sys$qiow",
  1793.         sys$qiow(QIOW_EFN, conchn, IO$_SENSEMODE, &wrk_iosb, 0, 0,
  1794.                  &ccold, sizeof(ccold), 0, 0, 0, 0))) return(-1);
  1795.         ccraw = cccbrk = ccold;
  1796.     }
  1797.     cgmf = 1;                /* Flag that we got them. */
  1798.     return(0);
  1799. }
  1800.  
  1801. /*  C O N C B --  Put console in cbreak mode.  */
  1802.  
  1803. /*  Returns 0 if ok, -1 if not  */
  1804.  
  1805. int
  1806. #ifdef CK_ANSIC
  1807. concb(char esc)
  1808. #else
  1809. concb(esc) char esc;
  1810. #endif /* CK_ANSIC */
  1811. /* concb */ {
  1812.     int x;
  1813.  
  1814.     debug(F101,"concb batch","",batch);
  1815.     if (batch) return(0);
  1816.     if (!cgmf) congm();            /* Get modes if necessary. */
  1817.     escchr = esc;            /* Make this available to other fns */
  1818.     ckxech = 1;                /* Program can echo characters */
  1819. /*
  1820.   Note: PASTHRU / PASSALL is what is preventing the Ctrl-C trap in the
  1821.   main program from working.  This business can be removed without any effect
  1822.   at all on the command parser -- everything still works: completion, ?-help,
  1823.   editing, etc.  The only problem is that Ctrl-Y is not trapped, so the
  1824.   program dies and leaves the terminal in no-echo mode.
  1825. */
  1826.     cccbrk.extended |= TT2$M_PASTHRU | TT2$M_ALTYPEAHD;
  1827.     if (parity)
  1828.       cccbrk.basic |= TT$M_NOECHO;
  1829.     else
  1830.       cccbrk.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  1831.     cccbrk.basic &= ~TT$M_ESCAPE;    /* Disable escape-seq processing */
  1832.     cccbrk.extended &= ~TT2$M_LOCALECHO; /* and local echoing */
  1833.     if (!CHECK_ERR("concb: sys$qiow",
  1834.     sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1835.                  &cccbrk, sizeof(cccbrk), 0, 0, 0, 0))) return(-1);
  1836.     debug(F100,"concb ok","",0);
  1837.     return(0);
  1838. }
  1839.  
  1840. /*  C O N B I N  --  Put console in binary mode  */
  1841.  
  1842. /*  Returns 0 if ok, -1 if not  */
  1843.  
  1844. int
  1845. #ifdef CK_ANSIC
  1846. conbin(char esc)
  1847. #else
  1848. conbin(esc) char esc;
  1849. #endif /* CK_ANSIC */
  1850. /* conbin */ {
  1851.  
  1852.     debug(F101,"conbin batch","",batch);
  1853.     if (batch) return(0);
  1854.     if (!cgmf) congm();            /* Get modes if necessary. */
  1855.     escchr = esc;            /* Make this available to other fns */
  1856.     ckxech = 1;                /* Program can echo characters */
  1857.     ccraw.extended |= TT2$M_PASTHRU | TT2$M_ALTYPEAHD;
  1858.     ccraw.basic &= ~TT$M_ESCAPE;    /* Disable escape-seq processing */
  1859.     ccraw.extended &= ~TT2$M_LOCALECHO;    /* and local echoing */
  1860.     if (parity)
  1861.       ccraw.basic |= TT$M_NOECHO;
  1862.     else
  1863.       ccraw.basic |= TT$M_NOECHO | TT$M_EIGHTBIT;
  1864.     ccraw.basic &= ~(TT$M_HOSTSYNC | TT$M_TTSYNC);
  1865.     if (!CHECK_ERR("conbin: sys$qiow",
  1866.     sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1867.                  &ccraw, sizeof(ccraw), 0, 0, 0, 0))) return(-1);
  1868.     return(0);
  1869. }
  1870.  
  1871.  
  1872. /*  C O N R E S  --  Restore the console terminal  */
  1873.  
  1874. int
  1875. conres() {
  1876.     debug(F101,"conres cgmf","",cgmf);
  1877.     if (!cgmf) return(0);        /* Do nothing if modes unknown */
  1878.     if (batch) return(0);
  1879.  
  1880.     msleep(250);            /*  not known! */
  1881.     ckxech = 0;                /* System should echo chars */
  1882.     if (!CHECK_ERR("conres: sys$qiow",
  1883.     sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1884.     &ccold, sizeof(ccold), 0, 0, 0, 0))) return(-1);
  1885.     debug(F100,"conres ok","",0);
  1886.     return(0);
  1887. }
  1888.  
  1889.  
  1890. /*  C O N R E S N E --  Restore the console terminal with No Echo */
  1891.  
  1892. int
  1893. conresne() {
  1894.     debug(F101,"conresne cgmf","",cgmf);
  1895.     if (!cgmf) return(0);        /* Don't do anything if modes unk */
  1896.     if (batch) return(0);
  1897.  
  1898.     msleep(250);
  1899.     ckxech = 1;                /* Program should echo chars */
  1900.  
  1901.     cctmp = ccold;
  1902.     cctmp.basic |= TT$M_NOECHO;
  1903.     if (!CHECK_ERR("conres: sys$qiow",
  1904.     sys$qiow(QIOW_EFN, conchn, IO$_SETMODE, &wrk_iosb, 0, 0,
  1905.     &cctmp, sizeof(cctmp), 0, 0, 0, 0))) return(-1);
  1906.     debug(F100,"conresne ok","",0);
  1907.     return(0);
  1908. }
  1909.  
  1910. /*  C O N O C  --  Output a character to the console terminal  */
  1911.  
  1912. int
  1913. #ifdef CK_ANSIC
  1914. conoc(char c)
  1915. #else
  1916. conoc(c) char c;
  1917. #endif /* CK_ANSIC */
  1918. /* conoc */ {
  1919.     if (batch) putchar(c);
  1920.     else
  1921.     if (!CHECK_ERR("conoc: sys$qiow",
  1922.         sys$qiow(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  1923.              &wrk_iosb, 0, 0, &c, 1, 0, 0, 0, 0))) return(-1);
  1924.     return(1);
  1925. }
  1926.  
  1927. /*  C O N X O  --  Write x characters to the console terminal  */
  1928.  
  1929. int
  1930. conxo(x,s) char *s; int x; {
  1931.     if (batch) fprintf(stdout, "%.*s", x, s);
  1932.     else if (!CHECK_ERR("conxo: sys$qiow",
  1933.     sys$qiow(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU,
  1934.          &wrk_iosb, 0, 0, s, x, 0, 0, 0, 0))) return(-1);
  1935.     return(0);
  1936. }
  1937.  
  1938. /*  C O N O L  --  Write a line to the console terminal  */
  1939.  
  1940. int
  1941. conol(s) char *s; {
  1942.     int len;
  1943.  
  1944.     if (batch) fputs(s, stdout);
  1945.     else {
  1946.     len = strlen(s);
  1947.     if (!CHECK_ERR("conol: sys$qiow",
  1948.         sys$qiow(QIOW_EFN, conchn, IO$_WRITEVBLK|IO$M_BREAKTHRU, &wrk_iosb,
  1949.              0, 0, s, len, 0, 0, 0, 0))) return(-1);
  1950.     }
  1951.     return(1);
  1952. }
  1953.  
  1954. /*  C O N O L A  --  Write an array of lines to console, with CRLFs added */
  1955.  
  1956. int
  1957. conola(s) char *s[]; {
  1958.     int i;
  1959.     char t[100], *cp;
  1960.  
  1961.     for (i=0 ; *s[i] ; i++) {
  1962.     strncpy(t,s[i],100);
  1963.     for (cp = t + strlen(t); --cp >= t;) {
  1964.         if (*cp != '\n' && *cp != '\r') {
  1965.         cp++;
  1966.         *cp++ = '\r'; *cp++ = '\n'; *cp++ = '\0';
  1967.         break;
  1968.         }
  1969.     }
  1970.     conol(t);
  1971.     }
  1972.     return(0);
  1973. }
  1974.  
  1975. /*  C O N O L L  --  Output a string followed by CRLF  */
  1976.  
  1977. int
  1978. conoll(s) char *s; {
  1979.     conol(s);
  1980.     conol("\r\n");
  1981.     return(1);
  1982. }
  1983.  
  1984.  
  1985. /*  C O N C H K  --  Check if characters available at console  */
  1986.  
  1987. int
  1988. conchk() {
  1989.     struct {
  1990.     unsigned short count;
  1991.     unsigned char first;
  1992.     unsigned char reserved1;
  1993.     long reserved2;
  1994.     } t;
  1995.  
  1996.     if (batch || backgrd) return(0);
  1997.     return(CHECK_ERR("conchk: sys$qiow",
  1998.     sys$qiow(QIOW_EFN, conchn, IO$_SENSEMODE|IO$M_TYPEAHDCNT, &wrk_iosb,
  1999.          0, 0, &t, sizeof(t), 0, 0, 0, 0)) ? t.count : 0);
  2000. }
  2001.  
  2002. /*  C O N I N C  --  Get a character from the console  */
  2003.  
  2004. int
  2005. coninc(timo) int timo; {
  2006.     int n = 0;
  2007.     unsigned char ch;
  2008.     int func, mask;
  2009.  
  2010.     if (batch) return(getchar());
  2011.     mask = 1 << CON_EFN;
  2012.     if (con_queued) {
  2013.     if (timo > 0) {
  2014.         struct { int hi, lo; } qtime;
  2015.         qtime.hi = -10*1000*1000*timo;  /* Max about seven minutes */
  2016.         qtime.lo = -1;
  2017.         sys$setimr(TIM_EFN, &qtime, 0, 0);
  2018.         mask |= TIM_EFN;
  2019.     }
  2020.     sys$wflor(CON_EFN, mask);
  2021.     sys$readef(CON_EFN, &mask);
  2022.     if (mask & (1 << CON_EFN)) {
  2023.         ch = (unsigned char) conch;
  2024.         CHECK_ERR("coninc: coniosb.status", coniosb.status);
  2025.         con_queued = 0;
  2026.     } else {
  2027.         ch = -1;
  2028.         vms_status = SS$_TIMEOUT;
  2029.     }
  2030.     } else {
  2031.     func = IO$_READVBLK | IO$M_NOFILTR;
  2032.     if (timo > 0) func |= IO$M_TIMED;
  2033.     CHECK_ERR("coninc: sys$qiow",
  2034.         sys$qiow(QIOW_EFN, conchn, func, &wrk_iosb,0,0,&ch,1,timo,0,0,0));
  2035.     }
  2036.     if (ch == '\r') ch = '\n';
  2037.  
  2038.     if (vms_status & 1) return(ch);
  2039.     return(-1);
  2040. }
  2041.  
  2042.  
  2043. /*  V M S _ G E T C H A R -- get a character from the console (no echo).
  2044.  *    Since we use raw reads, we must check for ctrl/c, ctrl/y and
  2045.  *    ctrl/z ourselves.  We probably should post a "mailbox" for
  2046.  *    ctrl/c and ctrl/y so the poor user can abort a runaway Kermit.
  2047.  *    Note: this routine intends for ctrl/z (eof) to be "permanent".
  2048.  *    Currently, no kermit routine calls "clearerror".  If this
  2049.  *    changes, the following code must be rewritten.
  2050.  */
  2051.  
  2052. int
  2053. vms_getchar() {
  2054.     register unsigned int ch;
  2055.     static int ateof = 0;
  2056.  
  2057.     if (ateof)
  2058.       return (EOF);
  2059.     ch = coninc(0);
  2060.     switch (ch) {
  2061.       case ('Y' - 64):
  2062.       case ('C' - 64):
  2063. #ifndef COMMENT
  2064. /*
  2065.   Just call the same handler that signal(SIGINT,xxx) would have invoked
  2066.   if Ctrl-C had been trapped.  The pointer to the handler was saved in
  2067.   cctrap by conint().
  2068. */
  2069.     if (cctrap)
  2070.       (*cctrap)(SIGINT,0);
  2071. #else
  2072.     ttclos(ttyfd);            /* Close down other terminal    */
  2073.     conres();            /* And cleanup console modes    */
  2074.     exit(SS$_ABORT);        /* Fatal exit.            */
  2075. #endif /* COMMENT */
  2076.       case ('Z' - 64):
  2077.     ateof = 1;
  2078.     return (EOF);
  2079.  
  2080.       default:
  2081.     return (ch);
  2082.     }
  2083. }
  2084.  
  2085. /*  C O N T T I  --  Get character from console then from tty  */
  2086. /*
  2087.   This is used in conect() when NO_FORK is defined.
  2088.   src is returned with 1 if the character came from the comm. line,
  2089.   0 if it was from the console, and with -1 if there was any error.
  2090. */
  2091. #ifdef TCPIPLIB
  2092. /*
  2093.  * Network/console read posted?
  2094.  */
  2095. static int    nettty_queued    = 0;
  2096. static int    netcon_queued    = 0;
  2097. #endif /* TCPIPLIB */
  2098.  
  2099. int
  2100. contti(c, src) int *c, *src; {
  2101.  
  2102. #ifndef TCPIPLIB
  2103.     int mask = 1<<CON_EFN | 1<<TTY_EFN;
  2104.     int x; unsigned char cc;
  2105.  
  2106. #else /* TCPIPLIB */
  2107.  
  2108. #define NET_EFN 7                /* Network event flag */
  2109.  
  2110.     int                mask;        /* Event flag mask */
  2111.  
  2112.     static CHAR            concc;        /* Console and network data */
  2113.     static CHAR            netcc;
  2114.  
  2115.     static struct iosb_struct    net_iosb;
  2116.     static struct iosb_struct    con_iosb;    /* IO status blocks */
  2117.  
  2118. /*
  2119.   Buffered network data, count, next character.  Declared in CKCNET.C ...
  2120. */
  2121.     extern CHAR            ttibuf[];
  2122.     extern int            ttibn;    
  2123.     extern int            ttibp;
  2124. #endif /* TCPIPLIB */
  2125.  
  2126.     *src = -1;                /* Assume there was an error */
  2127.  
  2128. #ifdef TCPIPLIB
  2129.     if (network) {            /* For active network connections */
  2130.     debug(F100,"contti network","",0);
  2131.  
  2132.     if (ttibn > 0) {
  2133.         /*
  2134.          * Handle the case where data remains in our "internal" buffer.
  2135.          * We need to:
  2136.          *
  2137.          *    -- Handle the console keyboard (is a character ready?)
  2138.          *    -- Return one character from the network buffer if not
  2139.          *
  2140.          * Post a new console read if necessary
  2141.          */
  2142.             if (!netcon_queued) {
  2143.                 if (!CHECK_ERR("contti: console sys$qio",
  2144.                             sys$qio(CON_EFN, conchn, IO$_READVBLK,
  2145.                     &con_iosb, 0, 0, &concc, 1,
  2146.                     0, 0, 0, 0))) return(-1);
  2147.                     netcon_queued = 1;
  2148.         }
  2149.         /*
  2150.          * Console character ready?
  2151.          */
  2152.                (void) sys$readef(CON_EFN, &mask);
  2153.  
  2154.             if (mask & (1 << CON_EFN)) {
  2155.             /*
  2156.              * Yes, return it
  2157.              */
  2158.             netcon_queued = 0;
  2159.  
  2160.              if (!CHECK_ERR("contti: con_iosb.status",
  2161.                     con_iosb.status)) return(-1);
  2162.  
  2163.             *c   = concc & 0xff;
  2164.                 *src = 0;
  2165.                 return(1);
  2166.         }
  2167.         /*
  2168.          * No console data; return buffered network character
  2169.          */
  2170.         ttibn--;
  2171.         *c   = ttibuf[ttibp++];
  2172.         *src = 1;
  2173.         return(1);
  2174.     }
  2175.     /*
  2176.      * No buffered data; post network and console reads
  2177.      */
  2178.         if (!nettty_queued) {
  2179. /*     -lt.  1992-09-14  begin */
  2180. /* All the event flag numbers should be obtained using lib$get_ef().
  2181.  * Using hard coded numbers, especially < 31 is tres dangerous!!!
  2182.  * Be careful, one must also change the event flag cluster used by
  2183.  * sys$readef. It is *not* just a simple matter of changing a few #defines.
  2184.  *
  2185.  * At least for DEC TCP/IP Services, socket calls return a proper file
  2186.  * descriptor (fd).  OpenVMS system services require a channel
  2187.  * (from sys$assign).  The two are *not* the same.  The call vaxc$get_sdc()
  2188.  * maps from a DEC TCP/IP fd to a channel.
  2189.  *
  2190.  * This is "gag me with a spoon" code, but it gets thing up and running.
  2191.  *
  2192.  */
  2193. #ifdef DEC_TCPIP
  2194.  
  2195.     {
  2196.        static int last_ttyfd = -1;
  2197.        static short int net_chan = -1;
  2198.  
  2199.     if (ttyfd != last_ttyfd){
  2200.         last_ttyfd = ttyfd;
  2201. #ifdef __DECC
  2202.         net_chan = (short) decc$get_sdc(last_ttyfd);
  2203. #else
  2204. #ifdef VAXC
  2205.         net_chan = vaxc$get_sdc(last_ttyfd);
  2206. #else
  2207. #        error CALL TO GET_SDC requires DECC or VAXC compiler!
  2208. #endif    /* VAXC */
  2209. # endif    /* DECC */
  2210.             }
  2211.  
  2212.             if (!CHECK_ERR("contti: network sys$qio",
  2213.                     sys$qio(NET_EFN, net_chan, IO$_READVBLK, &net_iosb, 0, 0,
  2214.                             &netcc, 1, 0, 0, 0, 0))) return(-1);
  2215.         }
  2216.  
  2217. #else /* Not DEC_TCPIP */
  2218.  
  2219.             if (!CHECK_ERR("contti: network sys$qio",
  2220.                     sys$qio(NET_EFN, ttyfd, IO$_READVBLK, &net_iosb, 0, 0,
  2221.                             &netcc, 1, 0, 0, 0, 0))) return(-1);
  2222. #endif /* DEC_TCPIP */
  2223.         nettty_queued = 1;
  2224.     }
  2225.  
  2226.         if (!netcon_queued) {
  2227.             if (!CHECK_ERR("contti: console sys$qio",
  2228.                     sys$qio(CON_EFN, conchn, IO$_READVBLK, &con_iosb,
  2229.                 0, 0, &concc, 1, 0, 0, 0, 0))) return(-1);
  2230.             netcon_queued = 1;
  2231.     }
  2232.     /*
  2233.      * Wait for a character
  2234.      */
  2235.         mask = (1 << CON_EFN) | (1 << NET_EFN);
  2236.  
  2237.         if (!CHECK_ERR("contti: sys$wflor",
  2238.                     sys$wflor(CON_EFN, mask))) return(-1);
  2239.  
  2240.         if (!CHECK_ERR("contti: sys$readef",
  2241.                     sys$readef(CON_EFN, &mask))) return(-1);
  2242.  
  2243.         if (mask & (1 << CON_EFN)) {
  2244.         /*
  2245.          * Console
  2246.          */
  2247.             if (!CHECK_ERR("contti: con_iosb.status",
  2248.                 con_iosb.status)) return(-1);
  2249.  
  2250.             *c         = concc & 0xff;
  2251.         *src       = 0;
  2252.             netcon_queued = 0;
  2253.  
  2254.         } else if (mask & (1 << NET_EFN)) {
  2255.         /*
  2256.          * Network
  2257.          */
  2258.         if (!(net_iosb.status & 1)) {
  2259.         /*
  2260.          * Network read error
  2261.          */
  2262. #ifdef WINTCP
  2263.         _$set_vaxc_error(SS$_NORMAL, net_iosb.status);
  2264.         win$perror("contti: net_iosb.status");
  2265. #else
  2266. #ifdef MULTINET
  2267. #ifdef COMMENT
  2268. /*
  2269.   When user hangs up, this prints an unnecessary scary message,
  2270.   like "Operation would block."
  2271. */
  2272.         socket_perror("contti: net_iosb.status");
  2273. #endif /* COMMENT */
  2274. #endif /* MULTINET */
  2275. #endif /* WINTCP */
  2276.         return(-1);
  2277.         }
  2278.  
  2279.         if (net_iosb.size == 0) {
  2280.         /*
  2281.          * Handle reset from remote
  2282.          */
  2283.         return(-1);
  2284.         }
  2285.         *c         = netcc & 0xff;
  2286.         *src       = 1;
  2287.             nettty_queued = 0;
  2288.         }
  2289.     } else                /* Not network */
  2290. #endif /* TCPIPLIB */
  2291.  
  2292. /*
  2293.   Should we worry about a network connection that's running under BATCH ?
  2294. */
  2295.     if (batch) {            /* Batch? */
  2296.     debug(F100,"contti batch","",0);
  2297.     if ((*c = getchar()) != EOF) {
  2298.         *src = 0;
  2299.     } else {
  2300.         *src = 1;
  2301.         *c = ttinc(0);
  2302.     }
  2303.     } else {                /* Interactive but not network */
  2304.  
  2305. #ifdef TTXBUF
  2306.     if (ttxbn > 0) {        /* Buffered port chars available */
  2307.  
  2308. /* Post a read on the console if one is not posted already */
  2309.  
  2310.         if (!con_queued) {
  2311.         if (!CHECK_ERR("contti: console sys$qio",
  2312.                  sys$qio(CON_EFN, conchn, IO$_READVBLK,
  2313.                      &coniosb, 0, 0,
  2314.                      &conch, 1, 0, 0, 0, 0)))
  2315.           return(-1);
  2316.         con_queued = 1;
  2317.         }
  2318.  
  2319. /* See if a console character has been read and if so, return it.  */
  2320.  
  2321.         (void) sys$readef(CON_EFN, &mask);
  2322.         if (mask & (1 << CON_EFN)) {
  2323.         con_queued = 0;
  2324.         if (!CHECK_ERR("contti: coniosb.status",
  2325.                    coniosb.status))
  2326.           return(-1);
  2327.         *c   = conch & 0xff;
  2328.         *src = 0;
  2329.         return(1);
  2330.         }
  2331.  
  2332. /* No console character, so return buffered port character */
  2333.  
  2334.         *c = ttinc(0);
  2335.         *src = 1;
  2336.         return(1);
  2337.     }
  2338.  
  2339. /* No buffered port data; post both network and console reads... */
  2340.  
  2341. #endif /* TTXBUF */
  2342.  
  2343.         mask = 1<<CON_EFN | 1<<TTY_EFN;    /* Event mask */
  2344.  
  2345.     debug(F101,"contti interactive mask","",mask);
  2346.  
  2347.         if (!con_queued) {        /* Console read not queued... */
  2348.             if (!CHECK_ERR("contti: console sys$qio",
  2349.             sys$qio(CON_EFN, conchn, IO$_READVBLK, &coniosb, 0, 0,
  2350.                     &conch, 1, 0, 0, 0, 0))) return(-1);
  2351.         con_queued = 1;
  2352.         debug(F100,"contti con_queued","",0);
  2353.     }
  2354.         if (!tt_queued) {        /* Port read not queued */
  2355.             if (!CHECK_ERR("contti: tty sys$qio",
  2356.             sys$qio(TTY_EFN, ttychn, IO$_READVBLK, &ttiosb, 0, 0,
  2357.                     &ttch, 1, 0, 0, 0, 0))) return(-1);
  2358.         tt_queued = 1;
  2359.         debug(F100,"contti tt_queued","",0);
  2360.     }
  2361.  
  2362. /* Wait for one of the queued reads to complete */
  2363.  
  2364.         if (!CHECK_ERR("contti: sys$wflor",
  2365.             sys$wflor(CON_EFN, mask))) return(-1);
  2366.     debug(F100,"contti sys$wflor ok","",0);
  2367.  
  2368. /* Read the event flags to see which read was completed */
  2369.  
  2370.         if (!CHECK_ERR("contti: sys$readef",
  2371.             sys$readef(CON_EFN, &mask))) return(-1);        
  2372.     debug(F100,"contti sys$readef ok","",0);
  2373.  
  2374.  
  2375. /* Return the character with the appropriate source (src) indicator */
  2376.  
  2377.         if (!(*src = ((mask & 1<<CON_EFN) ? 0 : 1))) {
  2378.             *c = conch;
  2379.             CHECK_ERR("contti: coniosb.status", coniosb.status);
  2380.             con_queued = 0;
  2381.         } else {
  2382.             *c = (ttprty ? ttch & 0177 : ttch);
  2383.         if (ttiosb.status == SS$_HANGUP) {
  2384.         fprintf(stderr,"\n%%CKERMIT-F-HANGUP, data set hang-up");
  2385.         *src = -1;
  2386.         return(1);
  2387.         }
  2388.             CHECK_ERR("contti: ttiosb.status", ttiosb.status);
  2389.             tt_queued = 0;
  2390.         }
  2391.         if (!(vms_status & 1)) *src = -1;
  2392.     }
  2393.     debug(F101,"contti *src","",*src);
  2394.     return((*src > -1) ? 1 : 0);
  2395. }
  2396.  
  2397. /*
  2398.   C A N C I O
  2399.   Cancel pending I/O requests on console and communication device.
  2400. */
  2401. VOID
  2402. cancio()  {
  2403. #ifdef NETCONN
  2404.     if (network) {
  2405. #ifdef TCPIPLIB
  2406. #ifdef DEC_TCPIP
  2407.     short int net_chan = -1;
  2408. #ifdef __DECC
  2409.     net_chan = (short) decc$get_sdc(ttyfd);
  2410. #else
  2411. #ifdef VAXC
  2412.     net_chan = vaxc$get_sdc(ttyfd);
  2413. #else
  2414. # error CALL TO GET_SDC requires DECC or VAXC compiler!
  2415. #endif    /* VAXC */
  2416. # endif    /* DECC */
  2417.         if (nettty_queued) (void) sys$cancel(net_chan);
  2418. #else
  2419.         if (nettty_queued) (void) sys$cancel(ttyfd);
  2420. #endif /* DEC_TCPIP */
  2421.         if (netcon_queued) (void) sys$cancel(conchn);
  2422.  
  2423.         netcon_queued = 0;
  2424.         nettty_queued = 0;
  2425.     return;
  2426. #else /* Not TCPIPLIB */
  2427.     return;
  2428. #endif /* TCPIPLIB */
  2429.     }
  2430. #endif /* NETCONN */
  2431.  
  2432.     if (!batch) {
  2433.         CHECK_ERR("cancio: console sys$cancel",
  2434.             sys$cancel(conchn));
  2435.         CHECK_ERR("cancio: tty sys$cancel",
  2436.             sys$cancel(ttychn));
  2437.         con_queued = 0;
  2438.         tt_queued = 0;
  2439.     }
  2440. }
  2441.  
  2442. /* get_qio_maxbuf_size()
  2443.  *
  2444.  * Get maximum size of QIO that can occur without getting the dreaded
  2445.  * exceeded quota status.
  2446.  */
  2447.  
  2448. #ifndef SYI$_MAXBUF
  2449. #define SYI$_MAXBUF 4175
  2450. #endif /* SYI$_MAXBUF */
  2451.  
  2452. int
  2453. get_qio_maxbuf_size(ttychn) unsigned long int ttychn; {
  2454.     unsigned char *tmpbuf;
  2455.     int unsigned long max=0;
  2456.     struct itmlst syiitm[] = { {2,SYI$_MAXBUF,(char *)&max,0},
  2457.             {0,0,0,0}};
  2458.  
  2459.     if (!ttychn) return(-1);
  2460.  
  2461.     if (!CHECK_ERR("get_qio_maxbuf_size: sys$getsyiw",
  2462.     sys$getsyiw(     0    /* efn */
  2463.             ,0    /* csidadr */
  2464.             ,0    /* nodename */
  2465.             ,&syiitm /* itmlst */
  2466.             ,&wrk_iosb /* iosb */
  2467.             ,0    /* astadr */
  2468.             ,0)))    /* astprm */
  2469.         exit(SS$_ABORT);        /* Fatal exit */
  2470.  
  2471.     if (!(tmpbuf = malloc(max)))
  2472.     return(0);
  2473.  
  2474.     for (; max > 0; max -= 16) {
  2475.     if (!test_qio(ttychn,max,tmpbuf)) /* (was &tmpbuf, caused crash) */
  2476.     {
  2477.         free(tmpbuf);
  2478.         return(max);
  2479.     }
  2480.     }
  2481.  
  2482.     free(tmpbuf);
  2483.     printf("\n%%CKERMIT-F-get_qio_maxbuf_size, Could not get maxbuf size\n");
  2484.     exit(SS$_ABORT);        /* Fatal exit */
  2485. }
  2486.  
  2487. int
  2488. test_qio(ttychn,max,dest)
  2489. unsigned long int ttychn;
  2490. long int max;
  2491. unsigned char *dest;
  2492. {
  2493.     static int trmmsk[2] = {0,0};
  2494.  
  2495. /*    trmmsk[1] = 1 << eol; */
  2496.  
  2497.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_READVBLK|IO$M_TIMED,
  2498.               &wrk_iosb, 0, 0, dest, max, 0, &trmmsk, 0, 0);
  2499.     return( !(vms_status & 1) ||
  2500.     (!(wrk_iosb.status & 1)) && wrk_iosb.status != SS$_TIMEOUT);
  2501. }
  2502.  
  2503.  
  2504. /*
  2505.  * Flush tt output buffer
  2506.  */
  2507.  
  2508. int
  2509. ttfluo() {
  2510.  
  2511.     long n=0;
  2512.  
  2513. #ifdef NETCONN
  2514.     if (network) return(0);
  2515. #endif /* NETCONN */
  2516.  
  2517.     if (!ttychn) return(-1);        /* Not open. */
  2518.  
  2519.     if (!CHECK_ERR("ttfluo: sys$qiow",
  2520.     sys$qiow(QIOW_EFN, ttychn, IO$_READVBLK|IO$M_TIMED|IO$M_PURGE,
  2521.          &wrk_iosb, 0, 0, &n, 0, 0, 0, 0, 0))) {
  2522.     perror("flush failed");
  2523.     return(-1);
  2524.     }
  2525.     return(0);
  2526. }
  2527.  
  2528. /*  T T G M D M  --  Get modem signals  */
  2529. /*
  2530.  Looks for the modem signals CTS, DSR, and CTS, and returns those that are
  2531.  on in as its return value, in a bit mask as described for ttwmdm.  Returns:
  2532.  -3 Not implemented
  2533.  -2 if the line does not have modem control
  2534.  -1 on error.
  2535.  >= 0 on success, with a bit mask containing the modem signals that are on.
  2536. */
  2537. int
  2538. ttgmdm() {
  2539.     struct {
  2540.     unsigned char type;
  2541.     unsigned char spare1;
  2542.     unsigned char modem;
  2543.     unsigned char spare2;
  2544.     unsigned long filler;
  2545.     } mdminfo;
  2546.     int retval;
  2547.  
  2548. #ifdef NETCONN
  2549.     if (network) return(-2);
  2550. #endif /* NETCONN */
  2551.     vms_status = sys$qiow(QIOW_EFN, ttychn, IO$_SENSEMODE|IO$M_RD_MODEM,
  2552.               &wrk_iosb, 0, 0, &mdminfo, 0, 0, 0, 0, 0);
  2553.  
  2554.     if (vms_status != SS$_NORMAL) {
  2555.     debug(F101,"ttgmdm serious error, status","",vms_status);
  2556.     return(-1);
  2557.     }
  2558.  
  2559.     debug(F101,"ttgmdm iosb","",wrk_iosb.status);
  2560.     debug(F101,"ttgmdm type","",mdminfo.type);
  2561.     debug(F101,"ttgmdm modem","",mdminfo.modem);
  2562.  
  2563.     if (wrk_iosb.status != SS$_NORMAL) {
  2564.     debug(F101,"ttgmdm iosb error, status","",wrk_iosb.status);
  2565.     return(-1);
  2566.     }
  2567.  
  2568. #ifdef DT$_LAT
  2569.     if (mdminfo.type == DT$_LAT) {
  2570.     debug(F101,"ttgmdm LAT port, no modem control","",0);
  2571.     return(-2);
  2572.     }
  2573. #endif /* DT$_LAT */
  2574.  
  2575.     if (mdminfo.type == 0) {
  2576.     debug(F101,"ttgmdm unknown driver, modem","",mdminfo.modem);
  2577.     return(-2);
  2578.     }
  2579.  
  2580.     retval = BM_DTR | BM_RTS;        /* Not visible, set by TTDRIVER */
  2581.     if (mdminfo.modem & TT$M_DS_CTS)
  2582.     retval |= BM_CTS;
  2583.     if (mdminfo.modem & TT$M_DS_DSR)
  2584.     retval |= BM_DSR;
  2585.     if (mdminfo.modem & TT$M_DS_CARRIER)
  2586.     retval |= BM_DCD;
  2587.     if (mdminfo.modem & TT$M_DS_RING)
  2588.     retval |= BM_RNG;
  2589.     return(retval);
  2590. }
  2591.  
  2592. /*
  2593.  * Return tty speed.  Speed is retreived from a qiow initially.
  2594.  * It is then changed only at user request.
  2595.  */
  2596. long
  2597. ttgspd() {
  2598.     extern int speed;
  2599. #ifdef NETCONN
  2600.     if (network) return(-1);        /* -1 if network connection */
  2601. #endif /* NETCONN */
  2602.     return(speed);
  2603. }
  2604.  
  2605.  
  2606. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  2607.  *
  2608.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  2609.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  2610.  *  2 = Auto: For "modem direct": The same as "Off".
  2611.  *            For real modem types: Heed carrier during connect, but ignore
  2612.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  2613.  *
  2614.  * As you can see, this setting does not affect dialing, which always ignores
  2615.  * carrier (unless there is some special exception for some modem type).  It
  2616.  * does affect ttopen() if it is set before ttopen() is used.  This setting
  2617.  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
  2618.  * (or should be) always called before any communications is tried, which
  2619.  * means that, practically speaking, the effect is immediate.
  2620.  *
  2621.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  2622.  *
  2623.  * Someone has yet to uncover how to manipulate the carrier in the BSD
  2624.  * environment (or any non-termio using environment).  Until that time, this
  2625.  * will simply be a no-op for BSD.
  2626.  *
  2627.  * Note that in previous versions, the carrier was most often left unchanged
  2628.  * in ttpkt()/ttvt() unless they were called with DIALING or CONNECT.  This
  2629.  * has changed.  Now it is controlled by ttcarr in conjunction with these
  2630.  * modes.
  2631.  */
  2632. int
  2633. ttscarr(carrier) int carrier; {
  2634.  
  2635.     return(-1);
  2636. }
  2637.  
  2638. int
  2639. psuspend(x) int x; {
  2640.  
  2641.     return(-1);
  2642. }
  2643.  
  2644. #ifdef CK_CURSES
  2645. /*
  2646.   tgetent() support for VMS curses emulation.
  2647.   Used by all three VMS fullscreen methods.
  2648.   Called from "SET FILE DISPLAY FULLSCREEN" in ckuus7.c.
  2649. */
  2650. int isvt52 = 0;                /* VT52/VT1xx flag */
  2651.  
  2652. int
  2653. tgetent(lp, term) char *lp, *term; {
  2654.     debug(F101,"tgetent terminal type","",ccold.type);
  2655.     debug(F101,"tgetent terminal extended","",ccold.extended);
  2656.  
  2657.     if ((ccold.type == DT$_VT5X) || (ccold.type == DT$_VT55)) {
  2658.     debug(F100,"tgetent VT5x","",0);
  2659.     isvt52 = 1;
  2660.     return(1);
  2661.     }
  2662.     if ((ccold.extended & TT2$M_ANSICRT) == TT2$M_ANSICRT) {
  2663.     debug(F100,"tgetent ANSICRT","",0);
  2664.     isvt52 = 0;
  2665.     return(1);
  2666.     }
  2667.     if ((ccold.extended & TT2$M_DECCRT) == TT2$M_DECCRT) {
  2668.     debug(F100,"tgetent DECCRT","",0);
  2669.     isvt52 = 0;
  2670.     return(1);
  2671.     }
  2672.     return(0);                /* Not a supported terminal type */
  2673. }
  2674. #endif /* CK_CURSES */
  2675.